From 66dacf9a405f93eccbadce33416523ad77574679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B3=E6=99=97?= Date: Tue, 28 Jul 2026 22:24:00 -0700 Subject: [PATCH] =?UTF-8?q?ci(release):=20=E5=8F=91=E7=89=88=E5=90=8E?= =?UTF-8?q?=E7=BB=99=E6=9C=AC=E7=89=88=E6=9C=AC=20PR=20=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E7=95=99=E3=80=8CReleased=20in=20vX.Y.Z=E3=80=8D=E8=AF=84?= =?UTF-8?q?=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub 原生侧栏那个「released in vX.Y.Z」徽标判定用的是 PR 分支的原始 head commit,squash 合并会把它变成孤儿 commit(即便 squash 出的新 commit 能从 tag 到达也不认)→ 用 squash 的 PR 永远不显示该徽标。实测 v3.7.1:#650/#631(merge commit)显示、#645/#646/#629(squash)不显示。 为「保持 squash 又能在 PR 上看到进了哪个版本」,发版后给本版本包含的每个 PR 留一条可见可点的时间线评论「🚀 Released in vX.Y.Z + release 链接」 作为等效替代。 实现(复用现有机制,不新增 API 扫描): - PR 列表直接来自 changelog 步骤已算好的 $RAW(type==pr 行去重),写到 released_prs.txt 交给新步骤,不再多打一次 /commits/{sha}/pulls - 只在 stable(latest)发版评论:canary/beta/rc/next 是灰度,评论会先刷 -canary 再刷正式版、既噪又误导,且对齐原生徽标只关心正式 Release 的语义 - fail-soft:npm+Release 此时已发布,评论失败不能让 job 失败 → continue-on-error + 单 PR 内部容错 - 幂等:重跑(如签名恢复 re-run)不重复刷,靠隐藏标记 `` 先查后发 - FD 3 读 PR 列表而非 stdin,避免循环内 gh 子进程吃掉后续 PR 行漏评论 - 纯直推(列表为空)自然 no-op - 新增 pull-requests: write 权限(原 job 仅 contents: write) 验证:python yaml.safe_load 通过;bash 端到端模拟证 PR 抽取去重、幂等 跳过、FD3 隔离无 stdin 泄漏(629 评论/645 幂等跳过/650 评论,无 LEAK)。 影响面:纯改 release.yml 的 release job,只在 stable tag-push 时多跑一步 评论;不动 npm publish/Release 创建/桌面资产/dist-tag 回滚 workflow。 不涉及运行时代码、跨平台/CLI/后端。 Co-Authored-By: Riff --- .github/workflows/release.yml | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 211ad2b65..c9d357ca6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,6 +128,12 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + # pull-requests: write —— 发版后给本版本包含的 PR 逐条留「Released in vX.Y.Z」 + # 评论(见下方 Comment "Released in" 步骤)。GitHub 原生那个侧栏 released 徽标 + # 判定用的是 PR 分支的原始 head commit,squash 合并会把它变成孤儿 commit → 徽标 + # 永远不显示(即便 squash 出的新 commit 能从 tag 到达也不行)。此权限用于发一条 + # 可见的时间线评论作为 squash 兼容的替代。 + pull-requests: write steps: - uses: actions/checkout@v6 with: @@ -287,6 +293,13 @@ jobs: done SECTIONS=$(node .github/scripts/changelog-sections.mjs < "$RAW") + # 复用上面已算好的 PR 列表(不再多打一次 API),抽出本版本包含的**去重** PR + # 号,持久化到 $RUNNER_TEMP,交给后面的「Comment "Released in"」步骤逐个留言。 + # 从 $RAW 里 type=='pr' 的行取第 2 列(PR number),排序去重。可能为空(纯直推 + # commit、无关联 PR)——那样评论步骤自然什么都不做。 + awk -F'\t' '$1=="pr"{print $2}' "$RAW" | sort -un > "$RUNNER_TEMP/released_prs.txt" + echo "PRs in this release: $(paste -sd' ' "$RUNNER_TEMP/released_prs.txt")" + { echo 'body<` 的评论,有就跳过。 + # - 只在有 PR 时动作;纯直推(released_prs.txt 为空)自然 no-op。 + continue-on-error: true + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + run: | + PR_FILE="$RUNNER_TEMP/released_prs.txt" + if [ ! -s "$PR_FILE" ]; then + echo "No PRs associated with this release; nothing to comment." + exit 0 + fi + RELEASE_URL="https://github.com/${GITHUB_REPOSITORY}/releases/tag/${RELEASE_TAG}" + MARKER="" + # 从 FD 3 读 PR 列表(而非 stdin),避免循环体内的 gh 子进程吃掉 stdin 里剩余的 + # PR 行导致漏评论。 + while read -r pr <&3; do + [ -n "$pr" ] || continue + # 幂等检查:该 PR 是否已有本版本的「已发布」评论 + if gh api "repos/${GITHUB_REPOSITORY}/issues/${pr}/comments" \ + --jq '.[].body' 2>/dev/null | grep -qF "$MARKER"; then + echo "PR #${pr}: already has released-in ${RELEASE_TAG} comment, skipping." + continue + fi + BODY="${MARKER} + 🚀 Released in [**${RELEASE_TAG}**](${RELEASE_URL})" + if gh pr comment "$pr" --repo "$GITHUB_REPOSITORY" --body "$BODY" 2>/dev/null; then + echo "PR #${pr}: commented released-in ${RELEASE_TAG}." + else + echo "PR #${pr}: comment failed (non-fatal), continuing." >&2 + fi + done 3< "$PR_FILE" + - name: Note — desktop assets pending # Make the npm-first window visible in the run log: npm + Release are # live now; the macOS .dmg/.zip attach in the parallel attach-desktop-assets