#!/usr/bin/env bash # ============================================================ # RainWeb 一键打包发布脚本 # 用法: # ./scripts/release.sh # 自动 patch 版本 +1(如 2.3.0 → 2.3.1) # ./scripts/release.sh 2.4.0 # 指定版本号 # ./scripts/release.sh --dry-run # 只预览版本号不执行 # ./scripts/release.sh --local # 本地打包:bump+build+源码包,不推送不发布 # # 流程:bump 版本 → build → commit+push → tag+push → 源码包 → Gitea release+附件 # --local 时:bump 版本 → build → 源码包(跳过 git push / tag / Gitea) # 依赖:npm、git、curl;Gitea 凭据在 ~/.git-credentials(token 自动提取) # ============================================================ set -euo pipefail cd "$(dirname "$0")/.." DRY="" LOCAL="" VERSION_ARG="" for a in "$@"; do case "$a" in --dry-run) DRY="1" ;; --local) LOCAL="1" ;; *) VERSION_ARG="${VERSION_ARG:-$a}" ;; esac done # ---------- 版本读取与计算 ---------- CURRENT=$(cat VERSION | tr -d ' \n') if [[ -n "$VERSION_ARG" ]]; then NEW_VERSION="$VERSION_ARG" else # patch +1:X.Y.Z → X.Y.(Z+1) NEW_VERSION=$(echo "$CURRENT" | awk -F. '{print $1"."$2"."($3+1)}') fi echo "当前版本: $CURRENT" echo "新版本: $NEW_VERSION" if [[ "$DRY" == "1" ]]; then echo "(--dry-run 预览结束)"; exit 0; fi if [[ "$CURRENT" == "$NEW_VERSION" ]]; then echo "⚠️ 版本未变化,退出"; exit 1; fi if [[ "$LOCAL" == "1" ]]; then echo "(本地打包模式:不推送、不建 tag、不发布 Gitea)" else read -p "确认发布 v$NEW_VERSION ? [y/N] " -r if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then echo "已取消"; exit 1; fi fi # ---------- 1. bump 版本(三处同步) ---------- echo "==> bump 版本" echo "$NEW_VERSION" > VERSION sed -i "s/\"version\": \"$CURRENT\"/\"version\": \"$NEW_VERSION\"/" package.json sed -i "s/\"version\": \"$CURRENT\"/\"version\": \"$NEW_VERSION\"/" package-lock.json # ---------- 2. 构建 ---------- echo "==> npm run build" npm run build # ---------- 3. 提交 + 推送(本地模式跳过) ---------- if [[ "$LOCAL" != "1" ]]; then echo "==> git commit + push" git add VERSION package.json package-lock.json git commit -m "chore: bump version $NEW_VERSION" git push origin master # ---------- 4. tag + 推送 ---------- echo "==> git tag v$NEW_VERSION" git tag "v$NEW_VERSION" git push origin "v$NEW_VERSION" fi # ---------- 5. 打源码包 ---------- echo "==> 打源码包" mkdir -p releases PKG="releases/rainweb-v$NEW_VERSION-src.tar.gz" tar czf "$PKG" \ --exclude='.git' --exclude='releases' --exclude='data' --exclude='uploads' \ --exclude='.env.json' --exclude='backups' --exclude='public/wallpaper' \ --exclude='node_modules' --exclude='*.log' \ . ls -lh "$PKG" # ---------- 6. Gitea release + 上传附件(本地模式跳过) ---------- if [[ "$LOCAL" == "1" ]]; then echo "✅ 本地打包完成: $PKG(未推送,可稍后手动发布)" exit 0 fi echo "==> 创建 Gitea release" # 从 ~/.git-credentials 提取 token(支持 http/https 两种格式) CRED=$(sed -n 's|https\?://\([^@]*\)@\(git\.rainnya\.asia\|[^/]*rainnya[^/]*\).*|\1|p' ~/.git-credentials 2>/dev/null | head -1) TOKEN=$(echo "$CRED" | sed 's/^[^:]*://') if [[ -z "$TOKEN" ]]; then echo "❌ 无法从 ~/.git-credentials 提取 Gitea token"; exit 1; fi # 提交说明:最近 5 条 commit BODY=$(git log --oneline -5 "v$CURRENT..HEAD" | sed 's/^/- /' || true) RELEASE_JSON=$(curl -s -X POST "https://git.rainnya.asia/api/v1/repos/miaomiao/rainblogweb/releases" \ -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ -d "{\"tag_name\":\"v$NEW_VERSION\",\"target_commitish\":\"master\",\"name\":\"v$NEW_VERSION\",\"body\":\"## v$NEW_VERSION\n\n$BODY\",\"draft\":false,\"prerelease\":false}") RELEASE_ID=$(echo "$RELEASE_JSON" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>{try{console.log(JSON.parse(d).id||'')}catch{console.log('')}})") if [[ -z "$RELEASE_ID" ]]; then echo "❌ release 创建失败: $(echo "$RELEASE_JSON" | head -c 200)" exit 1 fi echo "==> release id: $RELEASE_ID" echo "==> 上传附件" RESP=$(curl -s -X POST "https://git.rainnya.asia/api/v1/repos/miaomiao/rainblogweb/releases/$RELEASE_ID/assets?name=$(basename "$PKG")" \ -H "Authorization: token $TOKEN" -H "Content-Type: application/gzip" \ --data-binary "@$PKG" -w "\n%{http_code}") HTTP=$(echo "$RESP" | tail -1) if [[ "$HTTP" == "201" ]]; then echo "✅ 发布完成: https://git.rainnya.asia/miaomiao/rainblogweb/releases" else echo "❌ 附件上传失败 (HTTP $HTTP): $(echo "$RESP" | head -c 200)" exit 1 fi