diff --git a/.agents/skills/release/SKILL.md b/.agents/skills/release/SKILL.md index 02896fdfb..a0eefbe89 100644 --- a/.agents/skills/release/SKILL.md +++ b/.agents/skills/release/SKILL.md @@ -53,8 +53,9 @@ description: 准备或执行当前仓库发版,维护中文发布说明。用 ## 执行正式发版 调用入口前重新核对当前脚本的副作用、目标版本和待推送提交,保留无关工作区内容,不自动清理或暂存用户文件。 -当前脚本要求先提交 `release/notes.md`,再由脚本更新 `release/version.yaml` 并创建版本提交, -不要提前把版本文件改成目标版本,否则脚本会判定该版本已设置。 +先编辑 `release/notes.md`,保留为未提交改动(已暂存或未暂存均可);其他已跟踪文件的改动应先单独提交。 +脚本会更新 `release/version.yaml`,将它与最终工作区中的发布说明一起提交为 `chore(release): prepare vX.Y.Z`。 +不要提前单独提交说明或把版本文件改成目标版本;脚本要求说明相对 HEAD 有改动,并自行更新版本号。 本任务需要的提交按贡献文档保留英文 Conventional Commits 与相应署名。 在准备完成且用户已授权正式发布后,将 `release_version` 设为已确定的版本,执行: @@ -63,7 +64,7 @@ description: 准备或执行当前仓库发版,维护中文发布说明。用 release/publish "$release_version" ``` -该命令会创建版本提交与 annotated tag,原子推送分支和 tag,再从长期分支手动触发 `release.yml`。 +该命令会创建包含版本号和发布说明的单次提交与 annotated tag,原子推送分支和 tag,再从长期分支手动触发 `release.yml`。 它没有只读预演模式;不能为了检查或演练而执行。发布工作流读取 tag 中的说明,修改 tag 之后的本地文件不会改变该次构建。 ## 恢复与验收 diff --git a/.github/workflows/_quality.yml b/.github/workflows/_quality.yml index cca33851e..abd4963ce 100644 --- a/.github/workflows/_quality.yml +++ b/.github/workflows/_quality.yml @@ -205,3 +205,6 @@ jobs: rhysd/actionlint:1.7.7@sha256:887a259a5a534f3c4f36cb02dca341673c6089431057242cdc931e9f133147e9 -color .github/workflows/*.yml + + - name: Check release script syntax + run: bash -n release/publish diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bff3a77f..9b2b0d3cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: - main paths-ignore: - 'release/version.yaml' + - 'release/notes.md' pull_request: branches: - main diff --git a/release/publish b/release/publish index 5ec475761..c16352659 100755 --- a/release/publish +++ b/release/publish @@ -16,8 +16,9 @@ Usage: Example: release/publish 0.1.4 -Before publishing, replace release/notes.md with the new version's notes and -commit it. Its first line must be "# v". +Before publishing, replace release/notes.md with the new version's notes, +starting with "# v". Leave the notes uncommitted; this command commits +them together with release/version.yaml. Commit other tracked changes first. USAGE } @@ -94,11 +95,11 @@ remote_url="$(git remote get-url "$remote")" || die "failed to resolve remote UR repository="$(gh repo view "$remote_url" --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null)" || die "failed to resolve GitHub repository for $remote_url" -if ! git diff --quiet --ignore-submodules --; then - die "tracked files have unstaged changes; commit or stash them first" +if ! git diff --quiet --ignore-submodules -- . ":(exclude)$NOTES_FILE"; then + die "tracked files other than $NOTES_FILE have unstaged changes; commit or stash them first" fi -if ! git diff --cached --quiet --ignore-submodules --; then - die "index has staged changes; commit or unstage them first" +if ! git diff --cached --quiet --ignore-submodules -- . ":(exclude)$NOTES_FILE"; then + die "index has staged changes outside $NOTES_FILE; commit or unstage them first" fi current_version="$(read_version_key version)" @@ -108,6 +109,9 @@ current_version="${current_version#v}" tag="${TAG_PREFIX}${version}" git ls-files --error-unmatch "$NOTES_FILE" >/dev/null 2>&1 || die "$NOTES_FILE is not tracked" +if git diff HEAD --quiet -- "$NOTES_FILE"; then + die "$NOTES_FILE must have uncommitted changes so notes and version are committed together" +fi ruby - "$NOTES_FILE" "$tag" <<'RUBY' path, tag = ARGV lines = File.readlines(path) @@ -141,9 +145,9 @@ fi update_version_file "$version" -git add "$VERSION_FILE" +git add -- "$VERSION_FILE" "$NOTES_FILE" git commit \ - -m "chore: bump version to $version" \ + -m "chore(release): prepare $tag" \ -m "$SIGNATURE" git tag -a "$tag" -m "$tag"