Files
wenzi/scripts/ci/prd-gap-check.sh
Your Name 5f5597ef0f
Some checks failed
CI / build_test_package (push) Has been cancelled
CI / auto_merge (push) Has been cancelled
chore: sync project snapshot for gitea/github upload
2026-03-26 15:59:53 +08:00

251 lines
6.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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>
<summary>详细信息</summary>
\`\`\`
${details}
\`\`\`
</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}" >&2
local start_time=$(date +%s)
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输出避免stdout被命令替换捕获
local mvn_output_file="${TMP_DIR}/mvn-output.tmp"
mvn -B test -Dtest="${test_class}" \
-Djna.tmpdir="${JNA_TMP_DIR}" \
-Djava.io.tmpdir="${JAVA_TMP_DIR}" \
-Dmigration.test.strict=true \
-Dsurefire.failIfNoSpecifiedTests=true \
> "${mvn_output_file}" 2>&1
local test_exit_code=$?
# tee复制到证据文件
tee "${evidence_path}" < "${mvn_output_file}" > /dev/null
rm -f "${mvn_output_file}"
local end_time=$(date +%s)
local duration=$((end_time - start_time))
local result
if [[ ${test_exit_code} -eq 0 ]]; then
result="PASS"
else
result="FAIL"
fi
echo -e "${result}: ${test_name} (${duration}s)" >&2
# 返回退出码和证据路径,用冒号分隔
printf '%s:%s\n' "${test_exit_code}" "${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 test_result
if [[ -n "${test_method}" ]]; then
test_result="$(run_test "${test_spec}" "${test_class}#${test_method}")"
else
test_result="$(run_test "${test_spec}" "${test_class}")"
fi
# 解析退出码和证据路径
local test_exit_code="${test_result%%:*}"
local evidence_path="${test_result#*:}"
if [[ ${test_exit_code} -eq 0 ]]; then
add_check_result "${test_spec}" "PASS" "${evidence_path}" ""
passed_count=$((passed_count + 1))
else
local details
details="$(tail -50 "${evidence_path}" 2>/dev/null || echo "无日志")"
add_check_result "${test_spec}" "FAIL" "${evidence_path}" "${details}"
failed_count=$((failed_count + 1))
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=$((passed_count + 1))
else
local details=$(tail -50 "${build_log}" 2>/dev/null || echo "无日志")
add_check_result "Maven构建" "FAIL" "${build_log}" "${details}"
failed_count=$((failed_count + 1))
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 "$@"