问题:脚本里只有 docker tag / docker push,**没有 git tag**,所以远程仓库 一直只有软件包、没有版本 tag —— 「某个版本对应哪个提交」只能靠翻 CHANGELOG 猜。 镜像 tag 只说明「注册表里有这个包」,回答不了「这个包是哪份代码构建的」。 tools/push-all.sh: - 新增**版本预检**(传了版本号时):从 workbuddy_portal/__init__.py 读 __version__ 与传入值比对,不一致立刻退出 —— 放在最前面,免得代码和镜像 都推完了才发现「代码写着 1.4.0、却当 1.5.0 发」 - 新增 git tag -a vX.Y.Z + 推送该 tag,**放在代码与镜像都推成功之后**: tag 一旦出现在远端就是「这个版本发过了」的公开声明,不该先于产物出现 - 已存在的 tag 只提示、不改写(指向哪个提交由历史决定) 补打历史标签:v1.2.0 / v1.3.0 / v1.4.0,各指向引入该版本号的那个提交 (1.1.0 在仓库里没有对应提交,故未补)。 文档: - DEPLOYMENT 7.1 补上「为什么必须有 git tag」与版本预检说明 - DEPLOYMENT 7.4 补上「镜像与 tag 要分别核验」的命令(git ls-remote --tags) —— 此前 7.4 只验镜像,正是这个盲区让「没有 tag」一直没被发现 验证:python tools/check_docs.py → 0 处问题;python tools/smoke.py → ok=264 fail=0
110 行
4.9 KiB
Bash
可执行文件
110 行
4.9 KiB
Bash
可执行文件
#!/bin/sh
|
||
# SPDX-License-Identifier: MIT
|
||
# Copyright (c) 2026 Wang Chuanli
|
||
|
||
# =============================================================================
|
||
# 用 Gitea Access Token 一次性完成:推代码 + 推镜像(+ 打 git 版本 tag)
|
||
#
|
||
# export GITEA_TOKEN=<在 Gitea「设置 → 应用 → 生成令牌」创建,勾 repo + write:package>
|
||
# tools/push-all.sh # 推 main + 镜像 latest,不打版本 tag
|
||
# tools/push-all.sh 1.5.0 # 另外打 git tag v1.5.0 与镜像 tag 1.5.0
|
||
#
|
||
# 设计要点:
|
||
# * Token **只从环境变量读**,绝不写进 .git/config、URL 或任何文件。
|
||
# * 用 `-c credential.helper=` 屏蔽已配置的凭据助手(GCM),
|
||
# 否则在非交互会话里 GCM 会挂住等弹窗(连 /dev/tty 都拿不到,直接失败)。
|
||
# * 用 `http.extraHeader` 传 Basic 认证,比把 token 拼进 URL 更安全
|
||
# (不会落到 reflog / 进程列表里)。
|
||
# * git.iwali.top 有 Let's Encrypt 通配证书,**HTTPS 可用**,
|
||
# 所以镜像不需要配 insecure-registries。
|
||
#
|
||
# v1.5.0 起补上了 **git tag**(第 0 步与第 4 步):
|
||
# 在此之前脚本只打镜像 tag,于是远程仓库里永远只有软件包、没有 git tag ——
|
||
# 「某个版本对应哪个提交」只能靠翻 CHANGELOG 猜。现在版本号从
|
||
# `workbuddy_portal/__init__.py` 读,发布前先与前缀 v 的字面量对齐。
|
||
# =============================================================================
|
||
set -eu
|
||
|
||
HOST="${GITEA_HOST:-git.iwali.top}"
|
||
USER="${GITEA_USER:-wangchuanli}"
|
||
REPO="${GITEA_REPO:-workbuddy-portal}"
|
||
BRANCH="${GITEA_BRANCH:-main}"
|
||
TAG="${1:-}"
|
||
GIT_TAG=""
|
||
IMAGE="$HOST/$USER/$REPO"
|
||
|
||
: "${GITEA_TOKEN:?请先 export GITEA_TOKEN=<Gitea Access Token(repo + write:package)>}"
|
||
|
||
cd "$(dirname "$0")/.."
|
||
|
||
# ---------- 0. 版本一致性预检(早失败,别等代码和镜像都推完了才发现) ----------
|
||
if [ -n "$TAG" ]; then
|
||
GIT_TAG="v$TAG"
|
||
CODE_VER="$(sed -n 's/^__version__[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' \
|
||
workbuddy_portal/__init__.py | head -n 1)"
|
||
if [ "$CODE_VER" != "$TAG" ]; then
|
||
echo "ERROR: 代码里的版本是「$CODE_VER」,与要发布的「$TAG」不一致。" >&2
|
||
echo " 发布前请先把这四处改成同一个版本号(tools/check_docs.py 会校验):" >&2
|
||
echo " workbuddy_portal/__init__.py __version__" >&2
|
||
echo " Dockerfile org.opencontainers.image.version" >&2
|
||
echo " README.md 特性表里的 | 版本 | vX.Y.Z |" >&2
|
||
echo " docs/CHANGELOG.md 首个 ## [X.Y.Z] 标题" >&2
|
||
exit 1
|
||
fi
|
||
echo "==> 版本预检通过:代码与要发布的版本都是 $TAG"
|
||
fi
|
||
|
||
# ---------- 1. 推代码 ----------
|
||
echo "==> 推送代码到 https://$HOST/$USER/$REPO.git ($BRANCH)"
|
||
AUTH="$(printf '%s:%s' "$USER" "$GITEA_TOKEN" | base64 | tr -d '\r\n')"
|
||
git -c credential.helper= \
|
||
-c http.extraHeader="Authorization: Basic $AUTH" \
|
||
push -u origin "$BRANCH"
|
||
|
||
# ---------- 2. 构建镜像 ----------
|
||
echo "==> 构建镜像 $IMAGE:latest"
|
||
docker compose build
|
||
|
||
# ---------- 3. 登录并推镜像 ----------
|
||
echo "==> 登录 $HOST"
|
||
printf '%s' "$GITEA_TOKEN" | docker login "$HOST" -u "$USER" --password-stdin
|
||
|
||
echo "==> 推送 $IMAGE:latest"
|
||
docker push "$IMAGE:latest"
|
||
|
||
if [ -n "$TAG" ]; then
|
||
echo "==> 打版本标签并推送 $IMAGE:$TAG"
|
||
docker tag "$IMAGE:latest" "$IMAGE:$TAG"
|
||
docker push "$IMAGE:$TAG"
|
||
fi
|
||
|
||
# ---------- 4. git 版本 tag ----------
|
||
# 放在最后:**只有代码与镜像都推成功**才落 tag。
|
||
# tag 一旦出现在远端就是「这个版本发过了」的公开声明,不该先于产物出现。
|
||
if [ -n "$GIT_TAG" ]; then
|
||
if git rev-parse -q --verify "refs/tags/$GIT_TAG" >/dev/null; then
|
||
# 已存在就只提示、不报错:典型场景是「tag 早就打好了,这次只是补推代码」。
|
||
# 指向哪个提交由 git 决定,脚本不去改写已发布的 tag —— 那等于偷偷换掉
|
||
# 「v1.5.0 到底是哪份代码」这个答案。
|
||
AT="$(git rev-parse --short "$GIT_TAG^{commit}")"
|
||
HEAD_SHORT="$(git rev-parse --short HEAD)"
|
||
echo "==> git tag $GIT_TAG 已存在(指向 $AT)"
|
||
[ "$AT" = "$HEAD_SHORT" ] || echo " 注意:它不是当前 HEAD($HEAD_SHORT)—— 若这次改了代码,tag 不会跟着动。"
|
||
else
|
||
echo "==> 创建 git 注解 tag $GIT_TAG"
|
||
git tag -a "$GIT_TAG" -m "$REPO $GIT_TAG"
|
||
fi
|
||
echo "==> 推送 git tag $GIT_TAG"
|
||
git -c credential.helper= \
|
||
-c http.extraHeader="Authorization: Basic $AUTH" \
|
||
push origin "refs/tags/$GIT_TAG"
|
||
fi
|
||
|
||
echo
|
||
echo "完成。其他机器拉取:"
|
||
echo " docker pull $IMAGE:${TAG:-latest}"
|
||
if [ -n "$GIT_TAG" ]; then
|
||
echo "代码检出该版本:"
|
||
echo " git fetch --tags && git checkout $GIT_TAG"
|
||
fi
|