本仓库在上游 MediaCrawler 之上加了一整层(见 UPSTREAM.md),可合并流程默认 「有人知道上游动了」。而部署是 git pull --ff-only,只从自己的 Gitea 拉——上游的 提交不主动 fetch 就永远看不见。拖着不合并的代价是复利的:越久越难合。 于是把「上游动了没有」变成一条会自己跑、会推企业微信的通知: * api/monitor/upstream.py:git fetch <url> <branch> 到 FETCH_HEAD,用 rev-list --count HEAD..FETCH_HEAD 算落后数、FETCH_HEAD..HEAD 算领先数。 用 git 而非托管商 API,因为只有 git 知道共同祖先在哪——本仓库含有上游没有的 提交,直接比 tip 会得出错误结论。增量 fetch 只传几个新提交,不会遇到 UPSTREAM.md 里说的「大包必断」。 * 只 fetch 到 FETCH_HEAD:不配 remote、不写 refs/remotes、不碰索引与工作区, 所以不打断正在跑的采集,也不和 deploy.sh 的 git pull 抢锁。 * 挂在调度器 tick 上(不是采集,所以不看 is_busy、不受活跃时段限制——定时检查 放在半夜反而最合适),按 checked_at + 间隔 到期才跑;失败也写 checked_at, 于是 GitHub 不通时是每间隔重试一次,而不是每个 tick 撞一次墙。 * 同一个 tip 只推一次(记 tip 而不是「推过没」),上游真又动了会再推。 * 两个接口:GET /monitor/upstream 只读缓存;POST /monitor/upstream/check 手动 查一次且刻意不推通知——点按钮的人正看着结果。 * 默认关闭,间隔默认一天。 Dockerfile 显式装 git(python:slim 不带,而这是唯一的依赖);deploy.sh 顺带补上 一个真 bug 的提示:Dockerfile/requirements.txt 变了只 up -d 用的还是旧镜像。
72 lines
2.9 KiB
Bash
Executable File
72 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
#
|
||
# 更新这台机器上的部署。用法:
|
||
#
|
||
# ./deploy.sh
|
||
#
|
||
# 为什么需要脚本而不是一句 `git pull && docker compose up -d`:
|
||
# 前端产物 api/webui 是 gitignore 的(它由 vite 生成),git pull 带不过来。
|
||
# 所以代码更新之后必须在服务器上重建一次前端,否则页面还是旧的。
|
||
# 这一步在容器里做,好处是服务器不需要装 Node —— 只有 Docker。
|
||
#
|
||
# node_modules 和 npm 缓存都留在挂载目录内,重复构建不会重新下载。
|
||
set -euo pipefail
|
||
cd "$(dirname "$0")"
|
||
|
||
# 用镜像里的解释器跑,宿主机的 Python 版本无关。
|
||
IMAGE=mediacrawler:latest
|
||
|
||
before=$(git rev-parse HEAD)
|
||
git pull --ff-only
|
||
after=$(git rev-parse HEAD)
|
||
|
||
if [ "$before" = "$after" ]; then
|
||
echo "== 代码已是最新($after)"
|
||
else
|
||
echo "== 代码更新 $before -> $after"
|
||
git --no-pager log --oneline "$before..$after" | sed 's/^/ /'
|
||
fi
|
||
|
||
# 镜像层(依赖)改动只能靠重建,而这一步不是自动的:Dockerfile 或 requirements.txt 变了,
|
||
# 下面那句 `docker compose up -d --force-recreate` 用的是旧镜像,改动根本不会生效。
|
||
# 至少要说出来,否则现象是「代码明明更新了,功能却报缺依赖」。
|
||
if [ "$before" != "$after" ] && ! git diff --quiet "$before" "$after" -- Dockerfile requirements.txt; then
|
||
echo "!! Dockerfile / requirements.txt 有改动,需要重建镜像后重跑本脚本:"
|
||
echo " docker compose build"
|
||
fi
|
||
|
||
# 前端重建的两种情况:产物根本不存在(首次部署),或 webui/ 有改动。
|
||
if [ ! -f api/webui/index.html ]; then
|
||
need_build=1
|
||
reason="前端产物不存在"
|
||
elif [ "$before" != "$after" ] && ! git diff --quiet "$before" "$after" -- webui/; then
|
||
need_build=1
|
||
reason="webui/ 有改动"
|
||
else
|
||
need_build=0
|
||
reason=""
|
||
fi
|
||
|
||
if [ "$need_build" = "1" ]; then
|
||
echo "== 重建前端($reason)"
|
||
# -u 1000:1000 而不是 root:这里产出的文件要留在这个目录里给后面用,
|
||
# 以 root 生成的 node_modules 会让下次构建和人工清理都变得别扭。
|
||
# HOME 指向挂载目录,这样 npm 的缓存在宿主机上,重建时能复用。
|
||
docker run --rm \
|
||
-u 1000:1000 \
|
||
-w /app/webui \
|
||
-v "$PWD:/app" \
|
||
-e HOME=/app/webui \
|
||
-e npm_config_registry=https://registry.npmmirror.com \
|
||
"$IMAGE" sh -c 'npm ci --no-audit --no-fund && npm run build'
|
||
else
|
||
echo "== 前端无改动,跳过构建"
|
||
fi
|
||
|
||
# --force-recreate,而不是裸的 `up -d`:代码是 bind mount,容器配置和镜像都没变,
|
||
# 所以 `up -d` 会判定"无需变更"直接跳过,Python 代码的改动根本不会生效。前端产物是
|
||
# 磁盘上的静态文件,能即时生效,这一点很容易掩盖上面那个问题,直到有人改了 .py 才发现。
|
||
echo "== 重启容器"
|
||
docker compose up -d --force-recreate
|
||
docker compose ps
|