feat(release): 新增一键发布任务
This commit is contained in:
1 parent
b0f490a564
commit
8eb4cc8781
8 files changed
+449
-1
No files matched your search
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: xstats-release
|
||||
description: Execute, resume, or verify the XStats macOS client release workflow, including semver metadata, arm64 Developer ID signing, Apple notarization, c-ip object storage, regional update APIs, GitHub Release, Homebrew tap, and CI. Use for an actual XStats app release or a partial-release recovery; do not use for XStats Server development or server-image delivery.
|
||||
---
|
||||
|
||||
<!-- Copyright (C) 2026 ysicing -->
|
||||
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
||||
|
||||
# XStats Release
|
||||
|
||||
Release the XStats macOS client without letting its binary, Git tag, object-storage artifacts, update manifests, or Homebrew cask drift apart.
|
||||
|
||||
Before acting, read the repository `AGENTS.md`, the release section of `DEVELOPMENT.md`, `Taskfile.yml`, and `Scripts/release.sh` / `Scripts/publish_release.sh`. Treat the repository scripts as the current implementation; use [references/runbook.md](references/runbook.md) for the operational sequence and recovery checks.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Work in the repository containing this skill. Confirm it is the intended XStats checkout rather than assuming a fixed absolute path.
|
||||
- This skill covers the macOS app release only. Do not change the separate XStats Server repository, server image workflow, Cloudflare policy, Kubernetes workloads, or storage topology merely because a release touches their endpoints.
|
||||
- A request to inspect or prepare a release does not authorize commit, push, tag creation, uploads, API writes, Homebrew changes, or other external mutation. Require the user's explicit release or delivery instruction before those actions.
|
||||
- Do not create a PR unless the user explicitly requests one.
|
||||
- Never print, commit, persist in project files, or repeat signing credentials, storage keys, or `XSTATS_RELEASE_TOKEN`. Read secrets from an already authorized environment or credential store.
|
||||
|
||||
## Release invariants
|
||||
|
||||
- Public versions are semver from the first formal `CHANGELOG.md` heading; date-style versions are historical test data.
|
||||
- Release artifacts contain only arm64 binaries.
|
||||
- Public distribution uses `Developer ID Application`, hardened runtime, secure timestamps, notarization, stapling, and Gatekeeper acceptance. `Apple Development` and `SKIP_NOTARIZE=1` are not public-release substitutes.
|
||||
- The notarization keychain profile is `XStats` unless the user explicitly selects another valid profile.
|
||||
- Upload through the MinIO alias `c-ip` to `c-ip/oss/apps/macOS/XStats`; public downloads use `https://c.ysicing.net/oss/apps/macOS/XStats/`.
|
||||
- Publish the same appcast to the global and China release APIs. The manifest must remain last: packages first, then GitHub Release, then update APIs.
|
||||
- The Homebrew target is `ysicing/homebrew-tap`, installed as `ysicing/tap/xstats`.
|
||||
- `dist/release-provenance.json` binds artifacts to the build-time commit, version, build number, and version-file hashes. Do not bypass it or rebuild provenance manually.
|
||||
|
||||
## Execution shape
|
||||
|
||||
1. Establish a clean, current source baseline and pass repository tests/CI.
|
||||
2. Prepare only release metadata, then let `task release` advance `project.yml`, build, sign, notarize, staple, and generate `dist/`.
|
||||
3. Verify the installed app and generated artifacts before committing release metadata.
|
||||
4. Commit and push only the allowed metadata, then run the provenance verifier.
|
||||
5. Run the idempotent publish script and verify every external destination independently.
|
||||
|
||||
When the user explicitly authorizes the complete release, `task release-all` is the canonical one-command entry and includes commit, push, and every external publication. Use `task release` for build-only work and `task publish` to resume an already built and pushed release.
|
||||
|
||||
Stop rather than weakening a safety check when the source changed after the build, the tag points elsewhere, notarization is not accepted, public hashes differ, an API returns anything other than its expected success, or a credential is unavailable.
|
||||
|
||||
## Partial-release handling
|
||||
|
||||
- Determine the last proven stage before retrying. Object uploads, GitHub Release updates, API publication, and tap updates are separate facts.
|
||||
- Run `task publish` only after confirming the same provenance record and release commit; it invokes the idempotent publisher without rebuilding.
|
||||
- A Cloudflare response with `cf-mitigated: challenge` is an edge failure, not an application authentication failure. Use an already authorized clean egress when available; do not solve the challenge interactively or broadly disable protections.
|
||||
- If object upload fails, confirm the target is `c-ip`. Do not silently substitute `c`, `cos`, `home`, `ggy`, another bucket, or GitHub assets.
|
||||
- Never report completion from a successful build, upload, or tag alone. Completion requires the final verification checklist in the runbook.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Copyright (C) 2026 ysicing
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
interface:
|
||||
display_name: "XStats Release"
|
||||
short_description: "Build, notarize, publish, and verify XStats releases"
|
||||
default_prompt: "Use $xstats-release to publish and verify the next XStats macOS release."
|
||||
@@ -0,0 +1,155 @@
|
||||
<!-- Copyright (C) 2026 ysicing -->
|
||||
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
||||
|
||||
# XStats macOS release runbook
|
||||
|
||||
Use this runbook only for an actual release, resuming a partial release, or verifying one. Re-read the repository scripts first; if they disagree with this file, investigate the drift before mutating anything.
|
||||
|
||||
## 1. Preflight
|
||||
|
||||
From the XStats repository:
|
||||
|
||||
```bash
|
||||
git status -sb
|
||||
git fetch origin main
|
||||
git rev-parse HEAD
|
||||
git rev-parse origin/main
|
||||
task test
|
||||
./Scripts/version.sh
|
||||
```
|
||||
|
||||
Confirm:
|
||||
|
||||
- `HEAD` is the intended release source and is pushed before release metadata is prepared.
|
||||
- Existing working-tree changes are understood and limited to the release task.
|
||||
- The requested tag and GitHub Release do not already exist, unless this is an intentional idempotent resume.
|
||||
- The top changelog section contains the intended release content.
|
||||
|
||||
Check external prerequisites without exposing credentials:
|
||||
|
||||
```bash
|
||||
security find-identity -v -p codesigning
|
||||
xcrun notarytool history --keychain-profile XStats --output-format json
|
||||
mc stat c-ip/oss
|
||||
gh auth status
|
||||
```
|
||||
|
||||
The signing identity must be `Developer ID Application` with its private key. Merely having a valid `Apple Development` identity or a working notary profile is insufficient.
|
||||
|
||||
For the one-command path, `XSTATS_RELEASE_TOKEN` must already be available through an authorized environment or credential store. `task release-all` refuses to start when the token is absent, the branch is not `main`, `HEAD` differs from `origin/main`, or the release tag already exists.
|
||||
|
||||
## 2. Prepare version metadata
|
||||
|
||||
- Replace the first `## 未发布` heading with `## X.Y.Z · YYYY-MM-DD`.
|
||||
- Update the release badge in all four README files.
|
||||
- Do not manually change `project.yml`; `Scripts/version.sh release`, invoked by `task release`, writes the semver and increments the build number once.
|
||||
- Do not commit these metadata changes yet. They are allowed inputs to the provenance preflight.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 Scripts/release_provenance.py prepare
|
||||
git diff --check
|
||||
task release
|
||||
```
|
||||
|
||||
`task release` defaults to the `XStats` notary profile. Capture both Apple submission IDs and require `Accepted` for the app and DMG.
|
||||
|
||||
When the user explicitly authorizes commit, push, and all external publication, the canonical automated path is instead:
|
||||
|
||||
```bash
|
||||
task release-all
|
||||
```
|
||||
|
||||
It runs `task test`, performs the same release build, stages only allowed release metadata, commits and pushes it, then invokes `task publish`. After it returns, continue with the final verification section rather than repeating the manual commit or publish steps.
|
||||
|
||||
## 3. Verify local artifacts
|
||||
|
||||
Expected files:
|
||||
|
||||
```text
|
||||
dist/XStats-X.Y.Z-AppleSilicon.dmg
|
||||
dist/XStats-X.Y.Z-AppleSilicon.zip
|
||||
dist/appcast.json
|
||||
dist/xstats.rb
|
||||
dist/release-provenance.json
|
||||
```
|
||||
|
||||
`install_local.sh` moves the finished app to `/Applications`, so verify architecture and signatures there rather than assuming the DerivedData app still exists:
|
||||
|
||||
```bash
|
||||
lipo -archs /Applications/XStats.app/Contents/MacOS/XStats
|
||||
lipo -archs /Applications/XStats.app/Contents/MacOS/XStatsHelper
|
||||
lipo -archs /Applications/XStats.app/Contents/PlugIns/XStatsWidget.appex/Contents/MacOS/XStatsWidget
|
||||
codesign --verify --deep --strict --verbose=2 /Applications/XStats.app
|
||||
spctl -a -vv /Applications/XStats.app
|
||||
xcrun stapler validate dist/XStats-X.Y.Z-AppleSilicon.dmg
|
||||
spctl -a -t open --context context:primary-signature -vv dist/XStats-X.Y.Z-AppleSilicon.dmg
|
||||
```
|
||||
|
||||
All architectures must be `arm64`; both app and DMG must report notarized Developer ID acceptance. Validate the appcast JSON, artifact sizes, and SHA-256 values.
|
||||
|
||||
## 4. Commit release metadata
|
||||
|
||||
Stage only the intended release metadata, normally:
|
||||
|
||||
```text
|
||||
project.yml
|
||||
CHANGELOG.md
|
||||
README.md
|
||||
README.en.md
|
||||
README.ja.md
|
||||
README.ko.md
|
||||
```
|
||||
|
||||
Include `Assets/readme/activity.svg` and `Assets/readme/activity.zh.svg` only if this release actually changed them. Verify the staged list, commit with `chore(release): 发布 X.Y.Z`, and push only when authorized.
|
||||
|
||||
After pushing:
|
||||
|
||||
```bash
|
||||
python3 Scripts/release_provenance.py verify dist/release-provenance.json X.Y.Z BUILD
|
||||
```
|
||||
|
||||
The verifier must pass before uploads or tag creation.
|
||||
|
||||
## 5. Publish
|
||||
|
||||
Provide `XSTATS_RELEASE_TOKEN` through an authorized environment or credential store; never place it in a command transcript, repository file, or chat response. Then run the Task wrapper:
|
||||
|
||||
```bash
|
||||
task publish
|
||||
```
|
||||
|
||||
The script must use these defaults:
|
||||
|
||||
```text
|
||||
MC_TARGET=c-ip/oss/apps/macOS/XStats
|
||||
DOWNLOAD_BASE=https://c.ysicing.net/oss/apps/macOS/XStats
|
||||
TAP=ysicing/homebrew-tap
|
||||
```
|
||||
|
||||
Its required order is:
|
||||
|
||||
1. Verify provenance, clean worktree, and `HEAD == origin/main`.
|
||||
2. Upload DMG and ZIP to `c-ip`.
|
||||
3. Download each public `c.ysicing.net` URL and compare SHA-256.
|
||||
4. Create or update `vX.Y.Z` GitHub Release, refusing to move an existing mismatched tag.
|
||||
5. Publish the appcast to both regional APIs.
|
||||
6. Update `Casks/xstats.rb` in `ysicing/homebrew-tap`.
|
||||
|
||||
If manual recovery is unavoidable, preserve this order. Do not publish an appcast that references an unavailable object.
|
||||
|
||||
## 6. Final verification
|
||||
|
||||
Prove all of the following from live state:
|
||||
|
||||
- `git status -sb` is clean and local `main` matches `origin/main`.
|
||||
- The release tag resolves to the intended release metadata commit.
|
||||
- GitHub Release is neither draft nor prerelease and contains the notarized DMG with the expected digest.
|
||||
- Both public object URLs return bytes matching the local DMG and ZIP SHA-256 values.
|
||||
- Both regional update-check endpoints return the released version/build and `c.ysicing.net` URLs. Reuse one fixed validation installation ID instead of creating many statistics rows.
|
||||
- The remote Homebrew cask matches `dist/xstats.rb`; `brew info --cask ysicing/tap/xstats` shows the released version and arm64/macOS requirements.
|
||||
- The release commit and any immediate release-workflow fix commits have green GitHub Actions runs.
|
||||
- Temporary port forwards, credential aliases, debug pods, and staging directories created by this run are removed.
|
||||
|
||||
Report separate evidence for signing/notarization, object storage, GitHub Release, both update APIs, Homebrew, CI, and Git cleanliness. If any item is missing, call the release partial rather than complete.
|
||||
+3
-1
@@ -57,7 +57,9 @@ write the online-update zip and `appcast.json`, and write a Homebrew cask (`auto
|
||||
whose URLs point at the object storage prefix `https://c.ysicing.net/oss/apps/macOS/XStats`.
|
||||
The release records the source commit plus version-file hashes in `dist/release-provenance.json`;
|
||||
publishing accepts only a clean descendant that changed release metadata, so the Git tag cannot
|
||||
silently include source different from the packaged binaries. The helper derives its client
|
||||
silently include source different from the packaged binaries. `task release-all` runs tests, builds,
|
||||
commits and pushes only release metadata, then publishes every external target; `task publish`
|
||||
resumes the idempotent external half without rebuilding. The helper derives its client
|
||||
requirement from its own signing team at run time, so no team ID is hard-coded.
|
||||
|
||||
## Sampling
|
||||
|
||||
@@ -111,6 +111,20 @@ NOTARY_PROFILE=XStats task release
|
||||
`publish_release.sh` 会验证最终提交只改了允许的版本元数据,且工作区、版本文件与构建记录一致,
|
||||
避免安装包与 Git tag 对应源码不一致。
|
||||
|
||||
准备好 CHANGELOG 正式标题和四个 README 的版本徽章后,可用一个命令执行完整流程:
|
||||
|
||||
```bash
|
||||
# 需要提前通过安全环境提供 XSTATS_RELEASE_TOKEN;该命令会 commit、push 并写入所有发布目标
|
||||
task release-all
|
||||
```
|
||||
|
||||
它会依次运行测试、签名公证构建、精确暂存版本元数据、创建并推送 release commit,
|
||||
再上传对象存储、创建 GitHub Release、发布双区域清单并更新 Homebrew tap。
|
||||
如果 release commit 已推送后外部发布失败,修复外部问题后运行 `task publish` 续跑,
|
||||
不要再次运行 `task release-all`,否则会重复推进构建号。
|
||||
|
||||
需要逐阶段审阅或手工恢复时,按下面的分步流程执行。
|
||||
|
||||
打包完成后按顺序执行:
|
||||
|
||||
```bash
|
||||
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
# Copyright (C) 2026 ysicing
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# 一键执行完整发版:测试 → 签名公证构建 → 提交推送版本元数据 → 发布外部制品。
|
||||
# 调用这个脚本即授权本次 release commit、push、GitHub Release、对象存储、版本 API 与 Homebrew 写入。
|
||||
set -Eeuo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
if [ -z "${XSTATS_RELEASE_TOKEN:-}" ]; then
|
||||
echo "error: XSTATS_RELEASE_TOKEN 不能为空,一键发布尚未开始。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BRANCH="$(git symbolic-ref --quiet --short HEAD)" \
|
||||
|| { echo "error: 当前不是可发布的分支检出。" >&2; exit 1; }
|
||||
[ "$BRANCH" = main ] \
|
||||
|| { echo "error: 一键发布只能从 main 执行,当前是 ${BRANCH}。" >&2; exit 1; }
|
||||
|
||||
git fetch --quiet origin main
|
||||
HEAD_SHA="$(git rev-parse HEAD)"
|
||||
REMOTE_SHA="$(git rev-parse origin/main)"
|
||||
[ "$HEAD_SHA" = "$REMOTE_SHA" ] \
|
||||
|| { echo "error: HEAD 与 origin/main 不一致,请先处理未推送或远端更新。" >&2; exit 1; }
|
||||
|
||||
HEADING="$(grep -m1 '^## ' CHANGELOG.md || true)"
|
||||
if [[ "$HEADING" =~ ^##[[:space:]](0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)[[:space:]]·[[:space:]][0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
|
||||
VERSION="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
|
||||
else
|
||||
echo "error: CHANGELOG.md 顶部不是正式 semver 版本标题:${HEADING:-(没有二级标题)}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git ls-remote --exit-code --tags origin "refs/tags/v${VERSION}" >/dev/null 2>&1; then
|
||||
echo "error: v${VERSION} 已存在;若是恢复中断的发布,请运行 task publish。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RECOVERY=""
|
||||
on_error() {
|
||||
local status=$?
|
||||
case "$RECOVERY" in
|
||||
push)
|
||||
echo "error: release commit 已创建但尚未确认推送成功;请先运行 git push origin main。" >&2
|
||||
;;
|
||||
publish)
|
||||
echo "error: release commit 已推送;请修复外部问题后运行 task publish 续跑,不要再次执行 release-all。" >&2
|
||||
;;
|
||||
esac
|
||||
exit "$status"
|
||||
}
|
||||
trap on_error ERR
|
||||
|
||||
# 在投入签名和公证时间前拒绝任何未提交源码;版本元数据仍可按发布流程保持未提交。
|
||||
python3 Scripts/release_provenance.py prepare >/dev/null
|
||||
task test
|
||||
task release
|
||||
|
||||
BUILT_VERSION="$(sed -nE 's/^ *MARKETING_VERSION: *"?([0-9.]+)"?.*/\1/p' project.yml | head -1)"
|
||||
[ "$BUILT_VERSION" = "$VERSION" ] \
|
||||
|| { echo "error: 构建版本 $BUILT_VERSION 与 CHANGELOG 版本 $VERSION 不一致。" >&2; exit 1; }
|
||||
|
||||
# 构建后再次检查,防止构建工具或并行编辑把源码变化混入 release commit。
|
||||
python3 Scripts/release_provenance.py prepare >/dev/null
|
||||
RELEASE_FILES=(
|
||||
project.yml
|
||||
CHANGELOG.md
|
||||
README.md
|
||||
README.en.md
|
||||
README.ja.md
|
||||
README.ko.md
|
||||
Assets/readme/activity.svg
|
||||
Assets/readme/activity.zh.svg
|
||||
)
|
||||
git add -- "${RELEASE_FILES[@]}"
|
||||
if git diff --cached --quiet; then
|
||||
echo "error: 没有可提交的发布元数据。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git commit -m "chore(release): 发布 ${VERSION}"
|
||||
RECOVERY=push
|
||||
git push origin main
|
||||
RECOVERY=publish
|
||||
./Scripts/publish_release.sh
|
||||
RECOVERY=""
|
||||
|
||||
echo "✅ XStats ${VERSION} 完整发布完成"
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
# Copyright (C) 2026 ysicing
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
ROOT="$PWD"
|
||||
[ -f Scripts/release_all.sh ] || { echo "缺少 Scripts/release_all.sh" >&2; exit 1; }
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
setup() {
|
||||
rm -rf "${WORK:?}/repo" "${WORK:?}/bin"
|
||||
mkdir -p "$WORK/repo/Scripts" "$WORK/repo/Assets/readme" "$WORK/bin"
|
||||
cp "$ROOT/Scripts/release_all.sh" "$WORK/repo/Scripts/release_all.sh"
|
||||
chmod +x "$WORK/repo/Scripts/release_all.sh"
|
||||
cat > "$WORK/repo/project.yml" <<'YAML'
|
||||
settings:
|
||||
base:
|
||||
MARKETING_VERSION: "0.7.0"
|
||||
CURRENT_PROJECT_VERSION: "110"
|
||||
YAML
|
||||
cat > "$WORK/repo/CHANGELOG.md" <<'LOG'
|
||||
# 更新日志
|
||||
|
||||
## 0.8.0 · 2026-09-22
|
||||
|
||||
- 示例。
|
||||
LOG
|
||||
for file in README.md README.en.md README.ja.md README.ko.md; do
|
||||
printf '# XStats\n' > "$WORK/repo/$file"
|
||||
done
|
||||
: > "$WORK/repo/Assets/readme/activity.svg"
|
||||
: > "$WORK/repo/Assets/readme/activity.zh.svg"
|
||||
: > "$WORK/log"
|
||||
|
||||
cat > "$WORK/bin/git" <<'SH'
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
echo "git $*" >> "$RELEASE_ALL_TEST_LOG"
|
||||
case "${1:-}" in
|
||||
symbolic-ref) printf '%s\n' "${FAKE_BRANCH:-main}" ;;
|
||||
rev-parse) printf '%s\n' "${FAKE_SHA:-abc123}" ;;
|
||||
ls-remote) [ "${FAKE_TAG_EXISTS:-0}" = 1 ] ;;
|
||||
diff) [ "${3:-}" != --quiet ] ;;
|
||||
esac
|
||||
SH
|
||||
cat > "$WORK/bin/task" <<'SH'
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
echo "task $*" >> "$RELEASE_ALL_TEST_LOG"
|
||||
if [ "${1:-}" = release ]; then
|
||||
sed -i '' -E 's/(MARKETING_VERSION: *)"[^"]+"/\1"0.8.0"/' project.yml
|
||||
sed -i '' -E 's/(CURRENT_PROJECT_VERSION: *)"[^"]+"/\1"111"/' project.yml
|
||||
fi
|
||||
SH
|
||||
cat > "$WORK/bin/python3" <<'SH'
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
echo "python3 $*" >> "$RELEASE_ALL_TEST_LOG"
|
||||
printf 'abc123\n'
|
||||
SH
|
||||
cat > "$WORK/repo/Scripts/publish_release.sh" <<'SH'
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
echo publish >> "$RELEASE_ALL_TEST_LOG"
|
||||
SH
|
||||
chmod +x "$WORK/bin/git" "$WORK/bin/task" "$WORK/bin/python3" \
|
||||
"$WORK/repo/Scripts/publish_release.sh"
|
||||
}
|
||||
|
||||
expect_failure() {
|
||||
local message="$1"
|
||||
shift
|
||||
if "$@" >"$WORK/stdout" 2>"$WORK/stderr"; then
|
||||
echo "错误地成功:$message" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
setup
|
||||
expect_failure "缺少发布 token" env -u XSTATS_RELEASE_TOKEN \
|
||||
PATH="$WORK/bin:$PATH" RELEASE_ALL_TEST_LOG="$WORK/log" \
|
||||
"$WORK/repo/Scripts/release_all.sh"
|
||||
grep -q 'XSTATS_RELEASE_TOKEN' "$WORK/stderr" \
|
||||
|| { cat "$WORK/stderr" >&2; exit 1; }
|
||||
[ ! -s "$WORK/log" ] || { echo "缺少 token 时不应执行任何命令" >&2; exit 1; }
|
||||
|
||||
setup
|
||||
expect_failure "非 main 分支" env XSTATS_RELEASE_TOKEN=test FAKE_BRANCH=feature \
|
||||
PATH="$WORK/bin:$PATH" RELEASE_ALL_TEST_LOG="$WORK/log" \
|
||||
"$WORK/repo/Scripts/release_all.sh"
|
||||
grep -q 'main' "$WORK/stderr" || { cat "$WORK/stderr" >&2; exit 1; }
|
||||
grep -qx 'git symbolic-ref --quiet --short HEAD' "$WORK/log"
|
||||
|
||||
setup
|
||||
env XSTATS_RELEASE_TOKEN=test PATH="$WORK/bin:$PATH" RELEASE_ALL_TEST_LOG="$WORK/log" \
|
||||
"$WORK/repo/Scripts/release_all.sh"
|
||||
cat > "$WORK/expected" <<'LOG'
|
||||
git symbolic-ref --quiet --short HEAD
|
||||
git fetch --quiet origin main
|
||||
git rev-parse HEAD
|
||||
git rev-parse origin/main
|
||||
git ls-remote --exit-code --tags origin refs/tags/v0.8.0
|
||||
python3 Scripts/release_provenance.py prepare
|
||||
task test
|
||||
task release
|
||||
python3 Scripts/release_provenance.py prepare
|
||||
git add -- project.yml CHANGELOG.md README.md README.en.md README.ja.md README.ko.md Assets/readme/activity.svg Assets/readme/activity.zh.svg
|
||||
git diff --cached --quiet
|
||||
git commit -m chore(release): 发布 0.8.0
|
||||
git push origin main
|
||||
publish
|
||||
LOG
|
||||
diff -u "$WORK/expected" "$WORK/log"
|
||||
|
||||
echo "一键发布脚本测试通过"
|
||||
@@ -63,6 +63,16 @@ tasks:
|
||||
cmds:
|
||||
- ./Scripts/release.sh
|
||||
|
||||
publish:
|
||||
desc: 发布已构建且已提交推送的制品
|
||||
cmds:
|
||||
- ./Scripts/publish_release.sh
|
||||
|
||||
release-all:
|
||||
desc: 测试、构建、公证、提交推送并完成全部发布
|
||||
cmds:
|
||||
- ./Scripts/release_all.sh
|
||||
|
||||
stop:
|
||||
desc: 停止正在运行的 App
|
||||
cmds:
|
||||
@@ -74,6 +84,7 @@ tasks:
|
||||
cmds:
|
||||
- bash Scripts/version_test.sh
|
||||
- bash Scripts/arm64_release_test.sh
|
||||
- bash Scripts/release_all_test.sh
|
||||
- python3 Scripts/release_provenance_test.py
|
||||
- python3 Scripts/publish_api_test.py
|
||||
- task: test-api
|
||||
|
||||
Reference in new issue
Block a user