Skip to content

refactor(cli): improve publish-cli script reliability#441

Open
CheneyH wants to merge 3 commits into
mainfrom
feat/cli-auto-build
Open

refactor(cli): improve publish-cli script reliability#441
CheneyH wants to merge 3 commits into
mainfrom
feat/cli-auto-build

Conversation

@CheneyH
Copy link
Copy Markdown
Collaborator

@CheneyH CheneyH commented May 15, 2026

Summary

优化 publish-cli.sh 脚本的可靠性和用户体验:

  • 预检查前移:将版本计算和 tag/branch 冲突检测移到 build-and-test 之前执行,避免在发现冲突前浪费几分钟跑构建
  • 信号处理增强:trap 现在捕获 INT/TERM 信号(Ctrl+C),确保中断时正确清理工作树状态
  • 更新 Makefile 帮助文本:反映基于 PR 的发布流程

改进细节

1. 预检查前移(fail-fast)

之前git pullbun install / lint / typecheck / test / build(几分钟)→ 计算版本 → 检查 tag/branch 是否存在

现在git pull → 计算版本 → 检查 tag/branch 是否存在 → bun install / lint / typecheck / test / build

如果 release/cli-vX.Y.Z 分支或 tag 已存在(比如上次 PR 已合并但还没打 tag),现在会在几秒内报错退出,而不是白跑几分钟构建。

2. 信号处理增强

之前trap cleanup_on_error ERR — 只捕获命令失败

现在trap cleanup_on_error ERR INT TERM — 同时捕获 Ctrl+C 和 kill 信号

用户在 bun testbun build 阶段按 Ctrl+C 时,cleanup 函数会:

  • 恢复被 pre-* hook 弄脏的 cli/src/generated/pkg-info.ts
  • 确保以非零退出码退出(而不是误报成功)

Test plan

  • 语法检查通过(bash -n scripts/publish-cli.sh
  • 模拟冲突场景:手动创建 release/cli-vX.Y.Z 分支,验证脚本在 build 前就报错
  • 模拟中断场景:在 bun test 阶段按 Ctrl+C,验证工作树被正确恢复
  • 正常发布流程:跑一次完整的 make publish-cli patch(或在测试环境)

相关 PR

这是 #422 的后续优化,基于 code review 反馈改进脚本健壮性。

- Move version computation and pre-flight checks before build-and-test
  to fail fast on conflicts (existing branch/tag) instead of wasting
  minutes on lint/test/build
- Add INT/TERM signal handlers to cleanup trap so Ctrl+C during build
  properly restores working tree state
- Update Makefile help text to reflect PR-based workflow
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request transitions the CLI release process from a direct tag-and-push model to a more controlled pull-request-based workflow. The scripts/publish-cli.sh script has been significantly overhauled to include local validation steps (lint, typecheck, test, and build), automated version calculation, and PR creation via the GitHub CLI. Additionally, a state-machine-based cleanup mechanism was introduced to handle interruptions. Feedback suggested enhancing the reliability of this cleanup logic by using forced checkouts to ensure the working directory is correctly restored if the script fails after files have been staged.

Comment thread scripts/publish-cli.sh Outdated
Comment on lines +77 to +79
git -C "$REPO_ROOT" checkout -- "$PACKAGE_JSON" "$CLI_DIR/src/generated/pkg-info.ts" 2>/dev/null
git -C "$REPO_ROOT" checkout "$ORIGINAL_BRANCH" 2>/dev/null
git -C "$REPO_ROOT" branch -D "$RELEASE_BRANCH" 2>/dev/null
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

on-release 阶段的清理逻辑存在健壮性问题。如果脚本在 git add 之后但在 git commit 之前失败(例如在 generate-pkg-info.ts 阶段被中断或用户按下 Ctrl+C),git checkout -- <file> 仅会从索引(index)恢复文件。由于更改已被 add 到索引,工作区的更改将不会被撤销。这会导致随后的 git checkout "$ORIGINAL_BRANCH" 因为存在未提交的冲突更改而失败,最终导致脚本无法切回原分支并删除临时分支。建议使用 git checkout -f "$ORIGINAL_BRANCH" 强制切换并丢弃所有本地更改。

Suggested change
git -C "$REPO_ROOT" checkout -- "$PACKAGE_JSON" "$CLI_DIR/src/generated/pkg-info.ts" 2>/dev/null
git -C "$REPO_ROOT" checkout "$ORIGINAL_BRANCH" 2>/dev/null
git -C "$REPO_ROOT" branch -D "$RELEASE_BRANCH" 2>/dev/null
echo "" >&2
echo "[publish-cli] error before commit — rolling back release branch" >&2
git -C "$REPO_ROOT" checkout -f "$ORIGINAL_BRANCH" 2>/dev/null
git -C "$REPO_ROOT" branch -D "$RELEASE_BRANCH" 2>/dev/null

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已采纳建议并修复。使用 git checkout -f 强制切换分支,移除了冗余的 git checkout -- <file> 操作。这样即使文件已被 git add 到索引但未提交,也能可靠地清理并切回原分支。

修复已提交:4c7285b3

Comment thread scripts/publish-cli.sh Outdated
Comment on lines +84 to +85
git -C "$REPO_ROOT" checkout "$ORIGINAL_BRANCH" 2>/dev/null
git -C "$REPO_ROOT" branch -D "$RELEASE_BRANCH" 2>/dev/null
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

committed 阶段同样建议使用 git checkout -f。虽然此时更改已提交,工作区通常是干净的,但使用强制切换可以确保在任何意外情况下(如某些工具在后台修改了文件)都能可靠地返回原始分支并完成清理。

Suggested change
git -C "$REPO_ROOT" checkout "$ORIGINAL_BRANCH" 2>/dev/null
git -C "$REPO_ROOT" branch -D "$RELEASE_BRANCH" 2>/dev/null
git -C "$REPO_ROOT" checkout -f "$ORIGINAL_BRANCH" 2>/dev/null
git -C "$REPO_ROOT" branch -D "$RELEASE_BRANCH" 2>/dev/null

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已采纳建议。使用 git checkout -f 增强健壮性,确保在任何意外情况下都能可靠地返回原始分支并完成清理。

修复已提交:4c7285b3

CheneyH added 2 commits May 15, 2026 13:42
Address code review feedback from gemini-code-assist bot:

- Use `git checkout -f` in on-release and committed cleanup stages
  to ensure reliable branch switching even when files are staged
  but not committed (e.g., interrupted after `git add` but before
  `git commit`)
- Remove redundant `git checkout -- <file>` in on-release stage
  since `-f` already discards all local changes

This prevents cleanup failures when the script is interrupted
between staging and committing.
- Fix ERR trap bypass: remove `if !` wrapper around `gh pr create` so
  set -e triggers the trap and prints pushed-stage recovery instructions
- Fix command injection: all node -e/-p calls now use process.env
  instead of interpolating shell variables into JS string literals
- Rewrite cli/RELEASE.md to document the new PR-based release flow
- Rewrite scripts/tests/publish-cli-test.sh with 10 tests covering
  the new flow (stubs for bun/gh, pre-flight checks, happy path,
  cleanup state machine stages)
@CheneyH
Copy link
Copy Markdown
Collaborator Author

CheneyH commented May 15, 2026

Review findings addressed in efcf0ee

# Issue Resolution
Blocker 1 scripts/tests/publish-cli-test.sh all broken Fully rewritten — 10 tests covering new flow, all passing
Major 2 cli/RELEASE.md describes old tag-push flow Rewritten to document PR-based flow
Major 3 Commit message contains AI tool name Skipped — commit already on main, rewriting public history too costly
Major 4 Node -e command injection via string interpolation Fixed — all 3 node calls now use process.env
Bug if ! gh pr create bypasses ERR trap Fixed — direct call, set -e triggers trap correctly

Minor items 5/6/9 (EXIT trap, stderr suppression, trap cleanup inconsistency) are deferred — current code is safe because CLEANUP_STAGE=pre-branch at all explicit exit 1 points before branching.

Tests run:

$ bash scripts/tests/publish-cli-test.sh
[test] invalid bump type
[test] dirty working tree aborts
[test] non-main branch aborts
[test] gh auth failure aborts
[test] existing release branch aborts before build
[test] confirmation cancel leaves no side effects
[test] happy path pushes branch and opens PR
[test] baseline taken from latest cli-v* tag
[test] gh pr create failure triggers pushed-stage cleanup
[test] push failure rolls back local branch
all tests passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant