#!/usr/bin/env bash # # PRD-实现差距自动化检查脚本 # 生成可读的PRD差距报告,包含失败项和证据路径 # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)" TMP_DIR="${ROOT_DIR}/tmp/prd-gap-report" REPORT_FILE="${TMP_DIR}/prd-gap-report-$(date +%Y%m%d_%H%M%S).md" JAVA_TMP_DIR="${TMP_DIR}/java" JNA_TMP_DIR="${TMP_DIR}/jna" PODMAN_SOCK_PATH="/run/user/$(id -u)/podman/podman.sock" PODMAN_SOCK="unix://${PODMAN_SOCK_PATH}" PODMAN_LOG="${TMP_DIR}/podman-service.log" PODMAN_PID="" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color mkdir -p "${TMP_DIR}" "${JAVA_TMP_DIR}" "${JNA_TMP_DIR}" cleanup() { if [[ -n "${PODMAN_PID}" ]] && kill -0 "${PODMAN_PID}" >/dev/null 2>&1; then kill "${PODMAN_PID}" >/dev/null 2>&1 || true wait "${PODMAN_PID}" >/dev/null 2>&1 || true fi } trap cleanup EXIT # 初始化Podman(如果可用) init_podman() { if ! command -v podman >/dev/null 2>&1; then echo -e "${YELLOW}WARNING: podman 未安装,跳过容器测试${NC}" >&2 return 1 fi mkdir -p "$(dirname "${PODMAN_SOCK_PATH}")" podman system service --time=0 "${PODMAN_SOCK}" > "${PODMAN_LOG}" 2>&1 & PODMAN_PID=$! for _ in {1..30}; do if [[ -S "${PODMAN_SOCK_PATH}" ]] && podman --url "${PODMAN_SOCK}" info >/dev/null 2>&1; then echo -e "${GREEN}Podman service 就绪${NC}" return 0 fi sleep 1 done echo -e "${RED}ERROR: podman service 未就绪${NC}" >&2 return 1 } # 写入报告头 write_report_header() { cat > "${REPORT_FILE}" << 'EOF' # PRD-实现差距报告 > 自动生成时间: TIMESTAMP > 分支: BRANCH > 提交: COMMIT ## 执行摘要 | 检查项 | 状态 | 证据路径 | |--------|------|----------| EOF sed -i "s/TIMESTAMP/$(date '+%Y-%m-%d %H:%M:%S')/g" "${REPORT_FILE}" sed -i "s/BRANCH/$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')/g" "${REPORT_FILE}" sed -i "s/COMMIT/$(git rev-parse HEAD 2>/dev/null || echo 'unknown')/g" "${REPORT_FILE}" } # 添加检查结果到报告 add_check_result() { local name="$1" local status="$2" local evidence="$3" local details="$4" local status_icon if [[ "${status}" == "PASS" ]]; then status_icon="✅" elif [[ "${status}" == "FAIL" ]]; then status_icon="❌" else status_icon="⚠️" fi cat >> "${REPORT_FILE}" << EOF | | ${name} | ${status_icon} ${status} | ${evidence} | EOF if [[ -n "${details}" ]]; then cat >> "${REPORT_FILE}" << EOF
详细信息 \`\`\` ${details} \`\`\`
EOF fi } # 运行单个测试类并捕获结果 run_test() { local test_name="$1" local test_class="$2" # 清理test_class中的#和后续方法名,只保留类名作为文件路径 local clean_class="${test_class%%#*}" local evidence_path="${TMP_DIR}/test-results/${clean_class}.txt" mkdir -p "$(dirname "${evidence_path}")" echo -e "\n${YELLOW}运行测试: ${test_name}${NC}" local start_time=$(date +%s) local exit_code=0 if [[ -n "${PODMAN_SOCK}" ]] && [[ -S "${PODMAN_SOCK_PATH}" ]]; then export DOCKER_HOST="${PODMAN_SOCK}" fi export TESTCONTAINERS_RYUK_DISABLED="true" export JNA_TMPDIR="${JNA_TMP_DIR}" export JAVA_IO_TMPDIR="${JAVA_TMP_DIR}" mvn -B test -Dtest="${test_class}" \ -Djna.tmpdir="${JNA_TMP_DIR}" \ -Djava.io.tmpdir="${JAVA_TMP_DIR}" \ -Dmigration.test.strict=true \ -Dsurefire.failIfNoSpecifiedTests=true \ 2>&1 | tee "${evidence_path}" || exit_code=$? local end_time=$(date +%s) local duration=$((end_time - start_time)) local result if [[ ${exit_code} -eq 0 ]]; then result="PASS" else result="FAIL" fi echo -e "${result}: ${test_name} (${duration}s)" # 只输出证据路径到stdout,不输出其他内容 echo "${evidence_path}" } # 主流程 main() { echo -e "${GREEN}====== PRD-实现差距检查 ======${NC}" echo "报告输出目录: ${TMP_DIR}" # 初始化Podman if init_podman; then export DOCKER_HOST="${PODMAN_SOCK}" fi # 生成报告头 write_report_header # 定义要运行的PRD关键测试 declare -a TEST_CLASSES=( "AuditLogImmutabilityIntegrationTest" "PermissionCanonicalMigrationTest#shouldValidateCanonicalPermissionsAgainstBaseline" "PermissionCanonicalMigrationTest#shouldHaveZeroLegacyPermissionCodes" ) local failed_count=0 local passed_count=0 for test_spec in "${TEST_CLASSES[@]}"; do IFS='#' read -r test_class test_method <<< "${test_spec}" local evidence_path if [[ -n "${test_method}" ]]; then evidence_path=$(run_test "${test_spec}" "${test_class}#${test_method}") else evidence_path=$(run_test "${test_spec}" "${test_class}") fi if grep -q "BUILD SUCCESS" "${evidence_path}" 2>/dev/null; then add_check_result "${test_spec}" "PASS" "${evidence_path}" "" ((passed_count++)) else local details=$(tail -50 "${evidence_path}" 2>/dev/null || echo "无日志") add_check_result "${test_spec}" "FAIL" "${evidence_path}" "${details}" ((failed_count++)) fi done # 添加后端构建检查 echo -e "\n${YELLOW}运行后端构建检查${NC}" local build_exit_code=0 local build_log="${TMP_DIR}/maven-build.txt" mvn -B clean compile -DskipTests 2>&1 | tee "${build_log}" || build_exit_code=$? if [[ ${build_exit_code} -eq 0 ]]; then add_check_result "Maven构建" "PASS" "${build_log}" "" ((passed_count++)) else local details=$(tail -50 "${build_log}" 2>/dev/null || echo "无日志") add_check_result "Maven构建" "FAIL" "${build_log}" "${details}" ((failed_count++)) fi # 生成总结 cat >> "${REPORT_FILE}" << EOF ## 总结 - 通过: ${passed_count} - 失败: ${failed_count} - 生成时间: $(date '+%Y-%m-%d %H:%M:%S') EOF echo -e "\n${GREEN}====== 检查完成 ======${NC}" echo -e "通过: ${GREEN}${passed_count}${NC}" echo -e "失败: ${RED}${failed_count}${NC}" echo -e "报告: ${REPORT_FILE}" if [[ ${failed_count} -gt 0 ]]; then exit 1 fi exit 0 } main "$@"