#!/bin/bash # verify-worktree.sh — Verifica build, tests y cierre de issue en un worktree. # # Uso: # ./verify-worktree.sh [build-cmd] [test-cmd] # # Ejemplos: # ./verify-worktree.sh worktrees/0026-foo # ./verify-worktree.sh worktrees/0026-foo "go build -tags fts5 ./..." "go test -tags fts5 ./..." # BUILD_CMD="cmake --build cpp/build" TEST_CMD="ctest --test-dir cpp/build" ./verify-worktree.sh worktrees/0026-foo # # Resolucion de comandos (en orden de prioridad): # 1. Argumentos posicionales (build-cmd, test-cmd) # 2. Variables de entorno BUILD_CMD / TEST_CMD # 3. Archivo .parallel-fix-issues.yml en la raiz del worktree (claves: build, test) # 4. Auto-deteccion segun ficheros del proyecto: # - go.mod → "go build ./..." + "go test ./..." # - CMakeLists.txt → "cmake -S . -B build && cmake --build build" + "ctest --test-dir build" # - Cargo.toml → "cargo build" + "cargo test" # - package.json → "npm run build" + "npm test" # - pyproject.toml → "" + "pytest" # 5. Si nada se detecta, salta build/test con WARN. # # Auto-deteccion adicional: si hay go.mod, intenta extraer build tag de //go:build. # # Exit codes: # 0 = todo OK # 1 = error de argumento # 2 = build fallo # 3 = tests fallaron # 4 = issue no cerrado (solo WARN, no falla) # 5 = sin commits propios set -euo pipefail if [ $# -lt 1 ]; then echo "ERROR: se necesita el path del worktree" echo "Uso: $0 [build-cmd] [test-cmd]" exit 1 fi WORKTREE="$1" ARG_BUILD_CMD="${2:-}" ARG_TEST_CMD="${3:-}" # Resolver path absoluto if [[ "$WORKTREE" != /* ]]; then REPO_ROOT="$(git rev-parse --show-toplevel)" WORKTREE="${REPO_ROOT}/${WORKTREE}" fi if [ ! -d "$WORKTREE" ]; then echo "ERROR: worktree no encontrado: ${WORKTREE}" exit 1 fi SLUG="$(basename "$WORKTREE")" echo "=== Verificando: ${SLUG} ===" # --- Resolver build/test commands --- BUILD_CMD="${ARG_BUILD_CMD:-${BUILD_CMD:-}}" TEST_CMD="${ARG_TEST_CMD:-${TEST_CMD:-}}" # Manifest opcional MANIFEST="${WORKTREE}/.parallel-fix-issues.yml" if [ -z "$BUILD_CMD" ] && [ -f "$MANIFEST" ]; then M_BUILD=$(grep -E "^build:" "$MANIFEST" 2>/dev/null | sed -E 's/^build:[[:space:]]*"?([^"]*)"?[[:space:]]*$/\1/' | head -1 || true) if [ -n "$M_BUILD" ]; then BUILD_CMD="$M_BUILD"; echo "INFO: build desde manifest"; fi fi if [ -z "$TEST_CMD" ] && [ -f "$MANIFEST" ]; then M_TEST=$(grep -E "^test:" "$MANIFEST" 2>/dev/null | sed -E 's/^test:[[:space:]]*"?([^"]*)"?[[:space:]]*$/\1/' | head -1 || true) if [ -n "$M_TEST" ]; then TEST_CMD="$M_TEST"; echo "INFO: test desde manifest"; fi fi # Auto-deteccion if [ -z "$BUILD_CMD" ] || [ -z "$TEST_CMD" ]; then AUTO_BUILD="" AUTO_TEST="" if [ -f "${WORKTREE}/go.mod" ]; then # Detectar build tag AUTO_TAG=$(grep -rh "^//go:build " --include="*.go" "$WORKTREE" 2>/dev/null \ | sed -E 's|^//go:build ([a-zA-Z0-9_]+).*|\1|' \ | sort -u | head -1 || true) TAG_FLAG="" [ -n "$AUTO_TAG" ] && TAG_FLAG="-tags $AUTO_TAG" AUTO_BUILD="go build $TAG_FLAG ./..." AUTO_TEST="go test $TAG_FLAG ./..." echo "INFO: stack detectado: Go${TAG_FLAG:+ ($TAG_FLAG)}" elif [ -f "${WORKTREE}/CMakeLists.txt" ] || ls "${WORKTREE}"/cpp/CMakeLists.txt >/dev/null 2>&1; then CMAKE_DIR="." [ -f "${WORKTREE}/cpp/CMakeLists.txt" ] && [ ! -f "${WORKTREE}/CMakeLists.txt" ] && CMAKE_DIR="cpp" AUTO_BUILD="cmake -S ${CMAKE_DIR} -B ${CMAKE_DIR}/build -DCMAKE_BUILD_TYPE=Release && cmake --build ${CMAKE_DIR}/build -j" AUTO_TEST="ctest --test-dir ${CMAKE_DIR}/build --output-on-failure || true" echo "INFO: stack detectado: C++/CMake (dir=${CMAKE_DIR})" elif [ -f "${WORKTREE}/Cargo.toml" ]; then AUTO_BUILD="cargo build" AUTO_TEST="cargo test" echo "INFO: stack detectado: Rust" elif [ -f "${WORKTREE}/package.json" ]; then AUTO_BUILD="npm run build --if-present" AUTO_TEST="npm test --if-present" echo "INFO: stack detectado: Node" elif [ -f "${WORKTREE}/pyproject.toml" ] || [ -f "${WORKTREE}/setup.py" ]; then AUTO_BUILD="" # python normalmente no tiene build step AUTO_TEST="pytest" echo "INFO: stack detectado: Python" else echo "WARN: no se detecto stack; usar BUILD_CMD/TEST_CMD env o manifest .parallel-fix-issues.yml" fi [ -z "$BUILD_CMD" ] && BUILD_CMD="$AUTO_BUILD" [ -z "$TEST_CMD" ] && TEST_CMD="$AUTO_TEST" fi # 1. Verificar commits propios echo "" echo "--- Commits propios ---" COMMIT_COUNT=$(cd "$WORKTREE" && git log master..HEAD --oneline 2>/dev/null | wc -l) if [ "$COMMIT_COUNT" -eq 0 ]; then echo "FAIL: sin commits propios en la branch" exit 5 fi echo "OK: ${COMMIT_COUNT} commits desde master" cd "$WORKTREE" && git log master..HEAD --oneline # 2. Build echo "" if [ -n "$BUILD_CMD" ]; then echo "--- Build ($BUILD_CMD) ---" if (cd "$WORKTREE" && bash -c "$BUILD_CMD" 2>&1); then echo "OK: build exitoso" else echo "FAIL: build fallo" exit 2 fi else echo "--- Build SKIPPED (sin comando) ---" fi # 3. Tests echo "" if [ -n "$TEST_CMD" ]; then echo "--- Tests ($TEST_CMD) ---" if (cd "$WORKTREE" && bash -c "$TEST_CMD" 2>&1); then echo "OK: tests pasaron" else echo "FAIL: tests fallaron" exit 3 fi else echo "--- Tests SKIPPED (sin comando) ---" fi # 4. Issue cerrado echo "" echo "--- Cierre de issue ---" COMPLETED_FILES=$(cd "$WORKTREE" && git diff --name-only master -- dev/issues/completed/ 2>/dev/null | wc -l) if [ "$COMPLETED_FILES" -gt 0 ]; then echo "OK: issue movido a completed/" cd "$WORKTREE" && git diff --name-only master -- dev/issues/completed/ else echo "WARN: no se detecto issue movido a completed/ (verificar manualmente)" fi echo "" echo "=== RESULTADO: ${SLUG} — OK ==="