package_release.sh 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/env bash
  2. #
  3. # 打包 deployment/ 为可上传的 tar.gz 发布包
  4. # 用法: cd deployment && bash package_release.sh
  5. #
  6. set -euo pipefail
  7. export COPYFILE_DISABLE=1
  8. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  9. ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
  10. VERSION="${DATAOPS_RELEASE_VERSION:-$(date +%Y%m%d)}"
  11. ARCHIVE_NAME="dataops-platform-release-${VERSION}.tar.gz"
  12. OUTPUT_DIR="${DATAOPS_RELEASE_OUTPUT_DIR:-${ROOT_DIR}/dist}"
  13. required=(
  14. "${SCRIPT_DIR}/app"
  15. "${SCRIPT_DIR}/database"
  16. "${SCRIPT_DIR}/migrations"
  17. "${SCRIPT_DIR}/alembic.ini"
  18. "${SCRIPT_DIR}/requirements.txt"
  19. "${SCRIPT_DIR}/wsgi.py"
  20. "${SCRIPT_DIR}/gunicorn_config.py"
  21. "${SCRIPT_DIR}/deploy_dataops.sh"
  22. "${SCRIPT_DIR}/scripts/run_dataops.sh"
  23. "${ROOT_DIR}/scripts/edge_gateway_admin.py"
  24. "${ROOT_DIR}/deploy/edge/docker-compose.edge.yml"
  25. "${SCRIPT_DIR}/scripts/scan_release_secrets.py"
  26. "${ROOT_DIR}/docs/runbooks/EDGE_GATEWAY_OPERATIONS.md"
  27. "${ROOT_DIR}/docs/phase3/P3_WP04_EDGE_GATEWAY.md"
  28. "${ROOT_DIR}/docs/validation/P3_WP04_EDGE_GATEWAY_EVIDENCE.md"
  29. "${ROOT_DIR}/docs/validation/P3_WP04_FAILURE_INJECTION.json"
  30. "${ROOT_DIR}/docs/architecture/OPENAPI.yaml"
  31. "${SCRIPT_DIR}/dataops.env"
  32. )
  33. for path in "${required[@]}"; do
  34. if [[ ! -e "${path}" ]]; then
  35. echo "缺少发布文件: ${path}" >&2
  36. echo "请先执行: bash deployment/sync_release.sh" >&2
  37. exit 1
  38. fi
  39. done
  40. mkdir -p "${OUTPUT_DIR}"
  41. TMP_DIR="$(mktemp -d)"
  42. trap 'rm -rf "${TMP_DIR}"' EXIT
  43. RELEASE_ROOT="${TMP_DIR}/dataops-platform"
  44. mkdir -p "${RELEASE_ROOT}"
  45. copy_into_release() {
  46. local src="$1"
  47. local rel="$2"
  48. if [[ -e "${src}" ]]; then
  49. mkdir -p "$(dirname "${RELEASE_ROOT}/${rel}")"
  50. cp -a "${src}" "${RELEASE_ROOT}/${rel}"
  51. fi
  52. }
  53. copy_into_release "${SCRIPT_DIR}/app" "app"
  54. copy_into_release "${SCRIPT_DIR}/database" "database"
  55. copy_into_release "${SCRIPT_DIR}/migrations" "migrations"
  56. copy_into_release "${SCRIPT_DIR}/config" "config"
  57. copy_into_release "${SCRIPT_DIR}/scripts" "scripts"
  58. copy_into_release "${ROOT_DIR}/scripts/edge_gateway_admin.py" "scripts/edge_gateway_admin.py"
  59. copy_into_release "${ROOT_DIR}/deploy/edge" "deploy/edge"
  60. copy_into_release "${ROOT_DIR}/docs/runbooks/EDGE_GATEWAY_OPERATIONS.md" "docs/runbooks/EDGE_GATEWAY_OPERATIONS.md"
  61. copy_into_release "${ROOT_DIR}/docs/phase3/P3_WP04_EDGE_GATEWAY.md" "docs/phase3/P3_WP04_EDGE_GATEWAY.md"
  62. copy_into_release "${ROOT_DIR}/docs/validation/P3_WP04_EDGE_GATEWAY_EVIDENCE.md" "docs/validation/P3_WP04_EDGE_GATEWAY_EVIDENCE.md"
  63. copy_into_release "${ROOT_DIR}/docs/validation/P3_WP04_FAILURE_INJECTION.json" "docs/validation/P3_WP04_FAILURE_INJECTION.json"
  64. copy_into_release "${ROOT_DIR}/docs/architecture/OPENAPI.yaml" "docs/architecture/OPENAPI.yaml"
  65. copy_into_release "${SCRIPT_DIR}/requirements.txt" "requirements.txt"
  66. copy_into_release "${SCRIPT_DIR}/alembic.ini" "alembic.ini"
  67. copy_into_release "${SCRIPT_DIR}/wsgi.py" "wsgi.py"
  68. copy_into_release "${SCRIPT_DIR}/gunicorn_config.py" "gunicorn_config.py"
  69. copy_into_release "${SCRIPT_DIR}/__init__.py" "__init__.py"
  70. copy_into_release "${SCRIPT_DIR}/deploy_dataops.sh" "deploy_dataops.sh"
  71. copy_into_release "${SCRIPT_DIR}/dataops.env" "dataops.env"
  72. copy_into_release "${SCRIPT_DIR}/.env.production.example" ".env.production.example"
  73. copy_into_release "${SCRIPT_DIR}/README.md" "README.md"
  74. copy_into_release "${SCRIPT_DIR}/DEPLOYMENT_GUIDE.md" "DEPLOYMENT_GUIDE.md"
  75. copy_into_release "${SCRIPT_DIR}/CHECKLIST.md" "CHECKLIST.md"
  76. copy_into_release "${SCRIPT_DIR}/MANIFEST.md" "MANIFEST.md"
  77. # Runtime bytecode and AppleDouble metadata are never release inputs.
  78. find "${RELEASE_ROOT}" -type f \( -name '*.pyc' -o -name '*.pyo' -o -name '._*' \) -delete
  79. find "${RELEASE_ROOT}" -type d -name '__pycache__' -empty -delete
  80. # Scan every remaining regular file as UTF-8 text. This rejects encrypted or
  81. # unencrypted private-key blocks, binary/PKCS#12 stores, API-secret shapes and
  82. # literal credentials while permitting explicit replacement templates.
  83. "${PYTHON_BIN:-python3}" "${SCRIPT_DIR}/scripts/scan_release_secrets.py" "${RELEASE_ROOT}"
  84. (
  85. cd "${RELEASE_ROOT}"
  86. find . -type f ! -name SHA256SUMS -print | LC_ALL=C sort | while IFS= read -r item; do
  87. shasum -a 256 "${item}"
  88. done
  89. ) > "${RELEASE_ROOT}/SHA256SUMS"
  90. tar -czf "${OUTPUT_DIR}/${ARCHIVE_NAME}" -C "${TMP_DIR}" dataops-platform
  91. echo "发布包已生成: ${OUTPUT_DIR}/${ARCHIVE_NAME}"
  92. echo "上传后在服务器执行:"
  93. echo " tar -xzf ${ARCHIVE_NAME}"
  94. echo " cd dataops-platform"
  95. echo " sudo bash deploy_dataops.sh"