cc75bed133
Remove the repo top-level navigation logic and its accompanying explanatory comments from the post-receive hook. The previous code used `git rev-parse --absolute-git-dir` and `dirname` to determine and `cd` into the repository's top-level directory, which is no longer needed. The hook now starts directly with the nvm setup, making the script leaner and easier to maintain.
140 lines
5.9 KiB
Bash
Executable File
140 lines
5.9 KiB
Bash
Executable File
#!/bin/sh
|
||
# Post-receive hook: push 后自动 build + start
|
||
#
|
||
# 触发场景:
|
||
# - 非 bare repo + receive.denyCurrentBranch=updateInstead:本地推送自动部署
|
||
#
|
||
# 用途:执行 package.json 中的 `build` + `start` 脚本
|
||
# - 实际调用 `pnpm run build`(输出丢,仅记退出码)
|
||
# - 再后台启 `pnpm run start`(nohup,输出丢,hook 立即返回)
|
||
#
|
||
# 设计:逻辑块**封**装为独立函数,main 调**度**(shell 风格)
|
||
# - **全**局变量:LOG_FILE(在 init_log_file **里**定**义**)、CURRENT_BRANCH
|
||
# - **函**数**间**通过 `$LOG_FILE` / `$BUILD_EXIT` 通信
|
||
# - **不**用 set -e —— 各步**自**己处理错**误**(env 不**存**在 / build 失败 / 旧**进**程**不**存**在)→ 让 deploy 错**误****不**挡 git push
|
||
|
||
|
||
# 同 .bashrc **里**的 NVM **加**载逻辑
|
||
export NVM_DIR="$HOME/.nvm"
|
||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
||
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
|
||
|
||
# ============================================================
|
||
# 1. init_log_file —— 定**义** LOG_FILE + 创**建** logs/ 目**录**
|
||
# ============================================================
|
||
init_log_file() {
|
||
LOG_FILE="$(git rev-parse --show-toplevel)/logs/post-receive.log"
|
||
mkdir -p "$(dirname "$LOG_FILE")"
|
||
}
|
||
|
||
# ============================================================
|
||
# 2. write_metadata_header —— **覆**盖写**入**元信息(**首**次**写** → **覆**盖**让日志**开**头是**这**个)
|
||
# ============================================================
|
||
write_metadata_header() {
|
||
{
|
||
echo "=== post-receive @ $(date -u +%Y-%m-%dT%H:%M:%SZ) ==="
|
||
echo "branch: $(git rev-parse --abbrev-ref HEAD)"
|
||
echo "commit: $(git rev-parse --short HEAD)"
|
||
echo "cwd: $(pwd)"
|
||
echo ""
|
||
} > "$LOG_FILE"
|
||
}
|
||
|
||
# ============================================================
|
||
# 3. copy_env_by_branch —— 根**据**分支选 env-example → .env
|
||
# main 分支 → .env.production(prod 部署)
|
||
# test 分支 → .env.local(test **不**碰 .env.production,**避**免**读**到 prod 域名)
|
||
# dev 分支 → .env.local(**未**配远端**用**途,**但**保**留**)
|
||
# ============================================================
|
||
copy_env_by_branch() {
|
||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||
echo "=== branch: $CURRENT_BRANCH ===" >> "$LOG_FILE"
|
||
case "$CURRENT_BRANCH" in
|
||
main)
|
||
cp -f env-example/.env.production.example .env.production
|
||
echo "=== env: copied .env.production (main → prod) ===" >> "$LOG_FILE"
|
||
;;
|
||
test)
|
||
cp -f env-example/.env.local.example .env.local
|
||
echo "=== env: copied .env.local (test → test) ===" >> "$LOG_FILE"
|
||
;;
|
||
dev)
|
||
cp -f env-example/.env.development.example .env.local
|
||
echo "=== env: copied .env.local (dev → dev) ===" >> "$LOG_FILE"
|
||
;;
|
||
*)
|
||
echo "=== env: UNKNOWN branch '$CURRENT_BRANCH', skip env copy ===" >> "$LOG_FILE"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# ============================================================
|
||
# 4. run_build —— 跑 `pnpm run build`,输出**丢**,**捕**获退出码写日志
|
||
# 返回:build 退出码(main **用** if ! run_build 决**定**是否**继**续)
|
||
# ============================================================
|
||
run_build() {
|
||
echo "=== build START @ $(date -u +%Y-%m-%dT%H:%M:%SZ) ===" >> "$LOG_FILE"
|
||
pnpm run build > /dev/null 2>&1
|
||
BUILD_EXIT=$?
|
||
echo "=== build EXIT_CODE=$BUILD_EXIT @ $(date -u +%Y-%m-%dT%H:%M:%SZ) ===" >> "$LOG_FILE"
|
||
echo "" >> "$LOG_FILE"
|
||
return $BUILD_EXIT
|
||
}
|
||
|
||
# ============================================================
|
||
# 5. stop_existing_next —— 两阶段 kill + 等 1s 确**保**端口**完**全释放
|
||
# 1) 优**雅**关**闭**(SIGTERM)—— 旧**进**程**自**己 drain
|
||
# 2) 等 2s
|
||
# 3) 强杀(SIGKILL)—— **还**在**的**话
|
||
# 4) 等 1s
|
||
# ============================================================
|
||
stop_existing_next() {
|
||
echo "=== stop existing next @ $(date -u +%Y-%m-%dT%H:%M:%SZ) ===" >> "$LOG_FILE"
|
||
pkill -f "next start" 2>/dev/null
|
||
pkill -f "next-server" 2>/dev/null
|
||
sleep 2
|
||
pkill -9 -f "next start" 2>/dev/null
|
||
pkill -9 -f "next-server" 2>/dev/null
|
||
sleep 1
|
||
echo "=== stop DONE @ $(date -u +%Y-%m-%dT%H:%M:%SZ) ===" >> "$LOG_FILE"
|
||
echo "" >> "$LOG_FILE"
|
||
}
|
||
|
||
# ============================================================
|
||
# 6. launch_next —— 后**台**启 `pnpm run start`,捕 PID
|
||
# ============================================================
|
||
launch_next() {
|
||
echo "=== start LAUNCH @ $(date -u +%Y-%m-%dT%H:%M:%SZ) ===" >> "$LOG_FILE"
|
||
nohup pnpm run start > /dev/null 2>&1 &
|
||
START_PID=$!
|
||
echo "=== start PID=$START_PID @ $(date -u +%Y-%m-%dT%H:%M:%SZ) ===" >> "$LOG_FILE"
|
||
}
|
||
|
||
# ============================================================
|
||
# 7. log_abort —— build 失败**时**写**结**束**标**记(**不**输**出** START LAUNCH)
|
||
# ============================================================
|
||
log_abort() {
|
||
echo "=== ABORTED @ $(date -u +%Y-%m-%dT%H:%M:%SZ) (build failed, start skipped) ===" >> "$LOG_FILE"
|
||
}
|
||
|
||
# ============================================================
|
||
# main —— 调**度**所**有**步骤
|
||
# ============================================================
|
||
main() {
|
||
init_log_file
|
||
write_metadata_header # **先**覆盖写元信息(**这**样 env copy 日**志****能**保留在**后**面)
|
||
copy_env_by_branch # **追**加 env copy 日志
|
||
|
||
if ! run_build; then
|
||
log_abort
|
||
exit $BUILD_EXIT # build 失败 → **不**启 start(**避**免**用**旧 .next **跑**新代码)
|
||
fi
|
||
|
||
stop_existing_next # build 成功 → **先**关旧**进**程
|
||
launch_next # 再启新
|
||
}
|
||
|
||
main "$@"
|
||
|
||
exit 0
|