agent-Specialization/scripts/release_public.sh

180 lines
7.0 KiB
Bash
Executable File
Raw 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
# =============================================================================
# 公开发布脚本main → GitHub 公开仓库
#
# 机制:
# 1. 本地 public 分支为 orphan 分支(与 main 无共同历史),防止 main 历史中
# 曾出现过的敏感文件(如旧版 AGENTS.md随历史泄漏到公开仓库。
# 2. 内容来源是 `git archive main`(仅含被跟踪文件),未跟踪文件
# .env / node_modules / .astrion/ 等)天然不会混入。
# 3. 按 scripts/public_release_excludes.txt 剔除「被跟踪但不公开」的条目。
# 4. 发布前执行泄漏扫描(硬闸),命中即中止。
#
# 用法:
# bash scripts/release_public.sh # 交互式(摘要后逐确认 commit / push
# bash scripts/release_public.sh --dry-run # 只导出+扫描+展示摘要,不提交不推送
# bash scripts/release_public.sh --yes # 跳过确认(仅限已获得明确授权时)
# =============================================================================
set -euo pipefail
# ---- 配置 -------------------------------------------------------------------
PUBLIC_BRANCH="public" # 本地公开分支orphan
GITHUB_REMOTE="github" # GitHub remote 名
GITHUB_TARGET_BRANCH="main" # 推送到 GitHub 的目标分支
EXCLUDES_FILE="scripts/public_release_excludes.txt"
# 泄漏扫描模式(上下文特征,非裸词;避免误报公开信息如 GitHub 用户名)
LEAK_PATTERNS=(
'/Users/jojo'
'KOJO JOTARO'
'C:\\Users\\KOJO'
'cyjai\.com'
'git\.cyjai'
'正在修复中'
'astrion-clone'
'E:\\astrion'
)
# ---- 参数 -------------------------------------------------------------------
DRY_RUN=false
ASSUME_YES=false
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=true ;;
--yes) ASSUME_YES=true ;;
-h|--help)
grep '^#' "$0" | sed 's/^# \{0,1\}//' | head -20
exit 0 ;;
*) echo "未知参数: $arg"; exit 2 ;;
esac
done
confirm() { # $1=提示语
if $ASSUME_YES; then return 0; fi
local reply
read -r -p "$1 [y/N] " reply
[[ "$reply" == "y" || "$reply" == "Y" ]]
}
# ---- 前置检查 ---------------------------------------------------------------
cd "$(dirname "$0")/.."
echo "==> 仓库根: $(pwd)"
if ! git remote get-url "$GITHUB_REMOTE" >/dev/null 2>&1; then
echo "!! 未找到 remote '$GITHUB_REMOTE'。请先执行:"
echo " git remote add $GITHUB_REMOTE <GitHub 仓库地址>"
exit 1
fi
CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
if [[ "$CURRENT_BRANCH" != "main" ]]; then
echo "!! 当前分支是 $CURRENT_BRANCH,请先切换到 main。"
exit 1
fi
MAIN_SHA=$(git rev-parse --short main)
echo "==> 发布来源: main @ ${MAIN_SHA}(未提交到 main 的改动不会包含)"
# 工作区脏检测:未提交改动不会进入发布内容,明确警告防止「改了忘提交」
if [[ -n "$(git status --porcelain)" ]]; then
echo "!! 警告:工作区存在未提交改动,以下内容【不会】出现在本次发布中:"
git status --short | head -20
if ! $DRY_RUN; then
confirm "仍要基于 main 最新提交继续吗?" || { echo "已取消。请先提交或暂存改动。"; exit 1; }
fi
fi
# ---- 准备 public orphan 分支 ------------------------------------------------
if ! git show-ref --verify --quiet "refs/heads/$PUBLIC_BRANCH"; then
echo "==> 首次发布:创建 orphan 分支 '$PUBLIC_BRANCH'(空初始提交,与 main 无历史关联)"
EMPTY_TREE=$(git mktree </dev/null)
INIT_COMMIT=$(git commit-tree "$EMPTY_TREE" -m "chore: initialize public release branch")
git update-ref "refs/heads/$PUBLIC_BRANCH" "$INIT_COMMIT"
fi
# ---- 准备临时 worktree不碰当前工作区 -------------------------------------
WT=$(mktemp -d /tmp/astrion_public_release.XXXXXX)
cleanup() {
git worktree remove --force "$WT" >/dev/null 2>&1 || true
git worktree prune >/dev/null 2>&1 || true
}
trap cleanup EXIT
git worktree add --force "$WT" "$PUBLIC_BRANCH" >/dev/null
echo "==> 临时 worktree: $WT"
# 清空 worktree 内容(保留 .git保证被删除的文件能反映为删除
find "$WT" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
# ---- 导出 main 内容 ----------------------------------------------------------
git archive main | tar -x -C "$WT"
echo "==> 已从 main 导出被跟踪文件"
# ---- 按排除清单剔除 ----------------------------------------------------------
if [[ -f "$EXCLUDES_FILE" ]]; then
while IFS= read -r pattern; do
[[ -z "$pattern" || "$pattern" =~ ^[[:space:]]*# ]] && continue
target="$WT/${pattern%/}"
if [[ -e "$target" ]]; then
rm -rf "$target"
echo "==> 已剔除: $pattern"
fi
done < "$EXCLUDES_FILE"
else
echo "!! 警告:排除清单 $EXCLUDES_FILE 不存在"
fi
# ---- 泄漏扫描(硬闸) --------------------------------------------------------
echo "==> 执行泄漏扫描..."
LEAK_HIT=false
for pattern in "${LEAK_PATTERNS[@]}"; do
hits=$(grep -rInE --exclude-dir=.git --exclude=.git --exclude=release_public.sh -- "$pattern" "$WT" 2>/dev/null || true)
if [[ -n "$hits" ]]; then
LEAK_HIT=true
echo "!! 命中模式 [$pattern]:"
echo "$hits" | sed "s|$WT/||" | head -10
fi
done
if $LEAK_HIT; then
echo "!! 泄漏扫描未通过,已中止。请净化后重试,或确认误报后调整扫描模式。"
exit 1
fi
echo "==> 泄漏扫描通过"
# ---- 摘要 --------------------------------------------------------------------
cd "$WT"
git add -A
echo
echo "==================== 变更摘要(相对上一次公开提交) ===================="
git status --short | head -60
CHANGED=$(git status --short | wc -l | tr -d ' ')
TOTAL=$(find . -type f ! -path './.git/*' | wc -l | tr -d ' ')
echo "--------------------------------------------------------------------"
echo "变更条目: $CHANGED 公开文件总数: $TOTAL"
echo "======================================================================"
echo
if $DRY_RUN; then
echo "==> dry-run 结束(未提交、未推送)。临时 worktree 已自动清理。"
exit 0
fi
if [[ "$CHANGED" == "0" ]]; then
echo "==> 与上一次公开提交相比无变化。"
confirm "仍然创建一个空发布提交并推送吗?" || { echo "已取消。"; exit 0; }
fi
# ---- 提交 --------------------------------------------------------------------
DATE=$(date +%Y-%m-%d)
echo "==> 提交信息: release: sync from main @$MAIN_SHA ($DATE)"
confirm "确认在 '$PUBLIC_BRANCH' 分支上创建发布提交?" || { echo "已取消。"; exit 0; }
git commit -m "release: sync from main @$MAIN_SHA ($DATE)"
# ---- 推送 --------------------------------------------------------------------
echo "==> 推送目标: $GITHUB_REMOTE $PUBLIC_BRANCH:$GITHUB_TARGET_BRANCH"
confirm "确认推送到 GitHub公开仓库" || { echo "已取消推送(本地提交已保留)。 "; exit 0; }
git push "$GITHUB_REMOTE" "$PUBLIC_BRANCH:$GITHUB_TARGET_BRANCH"
echo "==> 完成。公开仓库已更新到 main @$MAIN_SHA 的快照。"