Files
XStats/Scripts/release.sh
T
ysicing f09861f6ec feat(release): 安装包迁移对象存储,版本号回归 semver
发布链路:安装包不再 scp 到 VPS,改用 mc 上传到对象存储
c.ysicing.net/oss/apps/macOS/XStats,上传后从 CDN 回读比对 sha256;
GitHub Release 挂 dmg 作为手动下载入口,应用内“手动下载”在未取到清单时
跳到 releases/latest。版本清单仍由自建 API 返回,publish_api.py 与
server/api 不变,且始终最后提交——安装包校验通过后客户端才看到新版本。
发布前只读校验 HEAD 与 origin/main 一致,脚本不代为 commit 或 push。

版本号:公开版本号从“年.月.日.索引”回归标准 semver,真源收敛到
CHANGELOG.md 顶部的 “## X.Y.Z · YYYY-MM-DD”;version.sh 收敛为
show/build/release 三个子命令,build 只推进构建号,删除 next 与 tag。
内部构建号改为单调递增整数(0109 规范化为 109)。日期校验回读比对,
因为 BSD date 会把 2026-02-29 规整成 2026-03-01 而非报错。

CI 不再参与发版:删除 tag 触发与 Set version from tag 步骤。

其他:appcast 的 changelog 指向本仓库而非上游站点;arm64_release_test
改用 fixture CHANGELOG,与仓库版本历史解耦;丢弃上游 0.2.0–0.6.1 的
历史条目;sync_changelog 不再改写 web/index.html(上游历史站点),
连带删除仅服务于它的 Website 段落。
2026-09-22 08:25:45 +08:00

150 lines
5.8 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.
#!/bin/bash
# 发布一个可分发的 Apple Silicon 版本:Developer ID 签名 → 公证 → 装订 → DMG(签名、公证、装订)
# → 在线升级包 → 版本清单 → Homebrew cask。
#
# ./Scripts/release.sh
#
# 需要钥匙串里的 Developer ID Application 证书和 notarytool 凭据。凭据按 Apple ID 与团队保存,
# 默认用 GiantAccel 开发者账号的 “GiantAccel” 凭据;也可以单独保存一份:
# xcrun notarytool store-credentials XStats --apple-id you@example.com --team-id <TEAM_ID>
# NOTARY_PROFILE=XStats ./Scripts/release.sh
#
# SKIP_NOTARIZE=1 只生成未公证的 DMG 供本机测试——不要分发,别的 Mac 上 Gatekeeper 会拒绝打开。
set -euo pipefail
cd "$(dirname "$0")/.."
# 安装包放在对象存储,由 Scripts/publish_release.sh 用 mc 上传
DOWNLOAD_BASE="${DOWNLOAD_BASE:-https://c.ysicing.net/oss/apps/macOS/XStats}"
DIST="${DIST:-dist}"
NOTARY_PROFILE="${NOTARY_PROFILE:-GiantAccel}"
SIGN_ID="${SIGN_ID:-$(security find-identity -v -p codesigning 2>/dev/null \
| grep 'Developer ID Application' | head -1 | sed -E 's/.*"(.*)".*/\1/' || true)}"
APP="build/DerivedData-arm64/Build/Products/Release/XStats.app"
if [ -z "$SIGN_ID" ]; then
echo "error: 钥匙串里没有 Developer ID Application 证书,无法发布。" >&2
exit 1
fi
TEAM_ID="$(echo "$SIGN_ID" | sed -nE 's/.*\(([A-Z0-9]+)\)$/\1/p')"
# 公开版本号取自 CHANGELOG.md 顶部的正式标题,同时推进一次内部构建号;
# 顶部还是 “## 未发布” 时脚本会在这里失败
VERSION="$(./Scripts/version.sh release)"
BUILD="$(sed -nE 's/^ *CURRENT_PROJECT_VERSION: *"?([0-9]+)"?.*/\1/p' project.yml | head -1)"
echo "版本 ${VERSION} · 签名身份:${SIGN_ID}"
notarize() {
echo "提交公证:$(basename "$1")(通常需要几分钟)…"
xcrun notarytool submit "$1" --keychain-profile "$NOTARY_PROFILE" --wait
}
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
rm -rf "$DIST"
mkdir -p "$DIST"
NAME="XStats-${VERSION}-AppleSilicon"
echo
echo "==== Apple Silicon(arm64)===="
# ---- 构建 ------------------------------------------------------------------
rm -rf "$APP"
task build CONFIG=Release INSTALL=0 BUMP=0 SIGN_ID="$SIGN_ID"
for binary in "$APP/Contents/MacOS/XStats" "$APP/Contents/MacOS/XStatsHelper" \
"$APP/Contents/PlugIns/XStatsWidget.appex/Contents/MacOS/XStatsWidget"; do
[ "$(lipo -archs "$binary")" = arm64 ] \
|| { echo "error: $binary 的架构是 $(lipo -archs "$binary"),应当只有 arm64" >&2; exit 1; }
done
codesign --verify --deep --strict --verbose=2 "$APP"
for binary in "$APP" "$APP/Contents/MacOS/XStatsHelper" "$APP/Contents/PlugIns/XStatsWidget.appex"; do
details="$(codesign -dvv "$binary" 2>&1)"
echo "$details" | grep -q "TeamIdentifier=${TEAM_ID}" \
|| { echo "error: $binary 未使用团队 ${TEAM_ID} 签名" >&2; exit 1; }
echo "$details" | grep -q "Timestamp=" \
|| { echo "error: $binary 缺少安全时间戳" >&2; exit 1; }
echo "$details" | grep -Eq "flags=.*runtime" \
|| { echo "error: $binary 未启用 Hardened Runtime" >&2; exit 1; }
done
# ---- 公证 App --------------------------------------------------------------
if [ "${SKIP_NOTARIZE:-0}" != "1" ]; then
# ditto 而不是 zip:保留包内的符号链接与扩展属性
ditto -c -k --keepParent "$APP" "$WORK/$NAME-notarize.zip"
notarize "$WORK/$NAME-notarize.zip"
xcrun stapler staple "$APP"
xcrun stapler validate "$APP"
if ! spctl -a -vv "$APP" 2>&1 | grep -q accepted; then
echo "error: Gatekeeper 仍然拒绝该 App,停止发布。" >&2
spctl -a -vv "$APP" || true
exit 1
fi
fi
# ---- DMG -------------------------------------------------------------------
rm -rf "$WORK/dmg"
mkdir -p "$WORK/dmg"
ditto "$APP" "$WORK/dmg/XStats.app"
ln -s /Applications "$WORK/dmg/Applications"
hdiutil create -volname "XStats ${VERSION}" -srcfolder "$WORK/dmg" -ov -format UDZO "$DIST/$NAME.dmg" >/dev/null
codesign --force --timestamp --sign "$SIGN_ID" "$DIST/$NAME.dmg"
if [ "${SKIP_NOTARIZE:-0}" != "1" ]; then
notarize "$DIST/$NAME.dmg"
xcrun stapler staple "$DIST/$NAME.dmg"
spctl -a -t open --context context:primary-signature -vv "$DIST/$NAME.dmg"
fi
# ---- 在线升级 ----------------------------------------------------------------
# 应用内升级下载已装订票据的 .app 压缩包
ditto -c -k --keepParent "$APP" "$DIST/$NAME.zip"
# 版本清单只包含 Apple Silicon 安装包
python3 Scripts/appcast.py "$VERSION" "$BUILD" "$DOWNLOAD_BASE" \
"$DIST/XStats-${VERSION}-AppleSilicon.zip" "$DIST/XStats-${VERSION}-AppleSilicon.dmg" > "$DIST/appcast.json"
# ---- Homebrew cask ------------------------------------------------------------
SHA_ARM="$(shasum -a 256 "$DIST/XStats-${VERSION}-AppleSilicon.dmg" | cut -d' ' -f1)"
cat > "$DIST/xstats.rb" <<CASK
cask "xstats" do
version "${VERSION}"
sha256 "${SHA_ARM}"
url "${DOWNLOAD_BASE}/XStats-#{version}-AppleSilicon.dmg"
name "XStats"
desc "Menu bar system monitor with fan control, keep-awake and cleanup"
homepage "https://github.com/ysicing/xstats"
# 应用内置在线升级,brew upgrade 默认不再重复升级
auto_updates true
depends_on arch: :arm64
depends_on macos: :sonoma
app "XStats.app"
zap trash: [
"~/Library/Logs/XStats",
"~/Library/Preferences/work.12306.xstats.app.plist",
]
end
CASK
# 本机只保留一份:把发布版装到 /Applications
./Scripts/install_local.sh "$APP"
echo
echo "✅ ${DIST}/${NAME}.dmg SHA-256 $(shasum -a 256 "$DIST/$NAME.dmg" | cut -d' ' -f1)"
echo " 在线升级:${DIST}/*.zip · ${DIST}/appcast.json"
echo " Homebrew cask:${DIST}/xstats.rb"
if [ "${SKIP_NOTARIZE:-0}" = "1" ]; then
echo "⚠️ 未公证,仅供本机测试。"
else
echo "下一步:提交并推送版本改动(project.yml、CHANGELOG.md、README 徽章),"
echo " 再运行 ./Scripts/publish_release.sh 上传安装包并发布。"
fi