#!/usr/bin/env bash
# 发新版的一条龙脚本。
#
# 用法:
# ./scripts/release.sh [] []
#
# 例:
# ./scripts/release.sh 1.0.02 A1004 docs/release-notes/1.0.02.md
# ./scripts/release.sh 1.0.02
#
# 流程:
# 1. 改 build-app.sh 里的 APP_VERSION / BUILD_NUMBER
# 2. 跑 build-app.sh 出 .app
# 3. ditto 打包成 OpenLess-.zip
# 4. sign_update zip → 拿 EdDSA 签名 + 长度
# 5. 在 appcast.xml 里追加新 -
# 6. git commit appcast.xml + build-app.sh
# 7. git tag v + push main + push tag
# 8. gh release create + 上传 zip
#
# 依赖:
# - /tmp/sparkle-tools/bin/sign_update(首次会自动从 Sparkle release 下载)
# - gh CLI 已登录
# - Keychain 里有 Sparkle EdDSA 私钥(已生成一次性)
set -euo pipefail
cd "$(dirname "$0")/.."
VERSION="${1:?用法: ./scripts/release.sh [] []}"
BUILD="${2:-}"
NOTES_FILE="${3:-}"
if [ -z "${BUILD}" ]; then
# 默认把 build number 设为 version 的简单变形(去掉点)。用户可显式覆盖。
BUILD="$(echo "${VERSION}" | tr -d '.')"
fi
APP_NAME="OpenLess"
APP_DIR="build/${APP_NAME}.app"
ZIP_NAME="${APP_NAME}-${VERSION}.zip"
ZIP_PATH="build/${ZIP_NAME}"
APPCAST="appcast.xml"
SPARKLE_TOOLS_DIR="/tmp/sparkle-tools"
SIGN_UPDATE="${SPARKLE_TOOLS_DIR}/bin/sign_update"
SPARKLE_VERSION="2.9.1"
# 1. 确保 sign_update 工具就位
if [ ! -x "${SIGN_UPDATE}" ]; then
echo "[release] 下载 Sparkle ${SPARKLE_VERSION} 工具..."
mkdir -p "${SPARKLE_TOOLS_DIR}"
(cd "${SPARKLE_TOOLS_DIR}" && \
gh release download "${SPARKLE_VERSION}" -R sparkle-project/Sparkle \
-p "Sparkle-${SPARKLE_VERSION}.tar.xz" --skip-existing && \
tar -xJf "Sparkle-${SPARKLE_VERSION}.tar.xz")
fi
# 2. 改 build-app.sh 里的版本
echo "[release] 写入版本号 ${VERSION} / ${BUILD}"
/usr/bin/sed -i '' "s/^APP_VERSION=.*/APP_VERSION=\"${VERSION}\"/" scripts/build-app.sh
/usr/bin/sed -i '' "s/^BUILD_NUMBER=.*/BUILD_NUMBER=\"${BUILD}\"/" scripts/build-app.sh
# 3. 构建 .app(不重置 TCC,避免本机权限被清掉)
echo "[release] 构建 .app"
RESET_TCC=0 ./scripts/build-app.sh > /dev/null
# 4. 打包 zip
rm -f "${ZIP_PATH}"
ditto -c -k --keepParent "${APP_DIR}" "${ZIP_PATH}"
ZIP_SIZE=$(/usr/bin/stat -f%z "${ZIP_PATH}")
echo "[release] zip = ${ZIP_PATH} (${ZIP_SIZE} bytes)"
# 5. 用 Keychain 里的 EdDSA 私钥签 zip
SIGN_OUTPUT=$("${SIGN_UPDATE}" "${ZIP_PATH}")
# 输出形如:sparkle:edSignature="xxxx" length="1234567"
EDSIG=$(echo "${SIGN_OUTPUT}" | /usr/bin/sed -n 's/.*sparkle:edSignature="\([^"]*\)".*/\1/p')
[ -n "${EDSIG}" ] || { echo "签名失败,sign_update 输出:${SIGN_OUTPUT}"; exit 1; }
echo "[release] EdDSA 签名 OK"
# 6. 准备 release notes(HTML 片段)
if [ -n "${NOTES_FILE}" ] && [ -f "${NOTES_FILE}" ]; then
NOTES_HTML=""
else
NOTES_HTML="OpenLess ${VERSION}
]]>"
fi
PUB_DATE=$(LC_ALL=C /bin/date -u +"%a, %d %b %Y %H:%M:%S +0000")
DOWNLOAD_URL="https://github.com/appergb/openless/releases/download/v${VERSION}/${ZIP_NAME}"
# 7. 在 appcast.xml 的标记行后插入新 -
TMP_ITEM=$(/usr/bin/mktemp)
cat > "${TMP_ITEM}" <
OpenLess ${VERSION}
${PUB_DATE}
${BUILD}
${VERSION}
15.0
${NOTES_HTML}
EOF
# sed 的 r 命令在匹配行后插入文件内容,比 awk -v 处理多行字符串更稳。
/usr/bin/sed -i '' "/OpenLess update feed<\/description>/r ${TMP_ITEM}" "${APPCAST}"
rm -f "${TMP_ITEM}"
echo "[release] appcast.xml 已追加 ${VERSION}"
# 8. git commit + tag + push
git add scripts/build-app.sh "${APPCAST}"
git commit -m "release: v${VERSION} (build ${BUILD})"
git tag "v${VERSION}"
git push origin main
git push origin "v${VERSION}"
# 9. gh release create + 上传 zip
gh release create "v${VERSION}" "${ZIP_PATH}" \
--title "OpenLess ${VERSION}" \
--notes-file "${NOTES_FILE:-/dev/stdin}" <