From 3a2bc2d282560d7a6fe1623a8ec80bfccadf0e0e Mon Sep 17 00:00:00 2001 From: ProjectNyaser <61904116+ProjectNyaser@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:07:25 +0800 Subject: [PATCH 1/5] =?UTF-8?q?refactor(ci):=20CI=20=E4=B8=8E=20Release=20?= =?UTF-8?q?=E5=90=88=E4=B8=80=E2=80=94=E2=80=94=E6=9D=A1=E4=BB=B6=E5=88=86?= =?UTF-8?q?=E6=B5=81=EF=BC=8C=E5=8F=91=E7=89=88=E4=B8=8D=E5=86=8D=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 此前 ci.yml + release.yml 双 workflow:发版 push --atomic 同推 master 与 tag → CI(pack-smoke)与 Release(build)各打一次包。合一为单 workflow: - check:全场景共用语法/结构冒烟(秒级) - pack:仅 pull_request / workflow_dispatch(打包验证产 artifact,PR 期保证链健康) - release:仅 tag v*(完整发版链:create-release → fetch-vendor + pack → 上传 zip/sha256 → verify 资产齐全 fail-closed) 发版时 branch push run 只跑 check(~6s),tag run 的 release job 是唯一打包点。 release job 内顺序 step(不再拆 create-release/build/verify 三 job——dispatch 复用已由 pack job 承接,无需保留独立 create-release)。 Co-authored-by: HanaAgent <313794804+HanaAgent@users.noreply.github.com> --- .github/workflows/ci.yml | 116 +++++++++++++++++++++++++++--- .github/workflows/release.yml | 130 ---------------------------------- 2 files changed, 105 insertions(+), 141 deletions(-) delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a673446..9bc7b02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,20 +1,25 @@ -# CI — 语法/结构冒烟 + 完整打包验证(零依赖,无 pnpm install) +# CI — 统一流程(条件分流,避免发版重复打包) # -# 触发: PR + push master +# 触发事件按场景分流(jobs 用 if 条件,单 workflow 覆盖全部): +# - pull_request → check + pack(打包验证,PR 期保证打包链健康) +# - push master(无 tag) → check only(打包已由 PR 期 pack 验证,不发版不重复打) +# - push tag v* → check + release(完整发版链,打包唯一发生点) +# - workflow_dispatch → check + pack(手动出包,产 artifact) # -# jobs: -# check: node --check 全部 js/mjs + manifest/skills 结构断言(快,秒级) -# pack-smoke: 完整打包链冒烟——fetch-vendor(cache 命中秒过)+ pack(产 zip/sha256) -# vendor 下载走 actions/cache(key 含 fetch-vendor.mjs hash:脚本变才重拉), -# PR 期即验证打包不坏,避免 tag 发版时才暴露 +# 为什么合一:此前 ci.yml + release.yml 双 workflow,发版时 push --atomic 同时推 +# master(触发 CI 的 pack-smoke)与 tag(触发 Release 的 build)→ 同一次发版打包两遍。 +# 合一后 tag 场景 release job 是唯一打包点,branch push run 只跑 check(~6s)。 name: CI on: pull_request: push: branches: [master] + tags: ['v*'] + workflow_dispatch: jobs: + # ---- 全场景共用:语法/结构冒烟(秒级) ---- check: runs-on: ubuntu-latest steps: @@ -36,16 +41,18 @@ jobs: node -e "const m=require('./manifest.json'); if(!m.id||!m.version) process.exit(1); console.log('manifest ok:', m.id, m.version)" test -f skills/gh/SKILL.md && echo "skills/gh ok" - pack-smoke: - runs-on: ubuntu-latest + # ---- PR / 手动:打包验证(产 artifact,3 天窗口) ---- + pack: + if: ${{ github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' }} needs: check + runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: 22 - # vendor 缓存:key 随 fetch-vendor.mjs(VERSIONS 表)变化,命中则免下载免解压 + # vendor 缓存:key 随 fetch-vendor.mjs(VERSIONS 表)变化,命中免下载免解压 - name: Cache vendor uses: actions/cache@v4 with: @@ -61,7 +68,7 @@ jobs: - name: Fetch vendor (git + gh + gnupg) run: node scripts/fetch-vendor.mjs - - name: Pack smoke + - name: Pack run: node scripts/pack.mjs - name: Verify package contents @@ -72,3 +79,90 @@ jobs: [ -f "$ZIP.sha256" ] || { echo "::error::no sha256 produced"; exit 1; } unzip -l "$ZIP" | grep -q "skills/gh/SKILL.md" && echo "skills/gh/SKILL.md in package" unzip -l "$ZIP" | grep -q "vendor/gnupg/bin/gpg.exe" && echo "vendor gnupg in package" + + - name: Upload artifacts + uses: actions/upload-artifact@v6 + with: + name: github-hanako-package + retention-days: 3 + path: releases/github-hanako-*.zip* + if-no-files-found: error + + # ---- tag:完整发版链(打包唯一发生点,不再与 CI 重复) ---- + release: + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + needs: check + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - uses: actions/setup-node@v5 + with: + node-version: 22 + + # 先建 release(pre-release,不占 latest;已存在跳过) + - name: Create release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then + echo "Release ${{ github.ref_name }} already exists, skipping create" + else + gh release create "${{ github.ref_name }}" \ + --prerelease \ + --title "${{ github.ref_name }}" \ + --generate-notes + fi + + - name: Cache vendor + uses: actions/cache@v4 + with: + path: | + vendor + _tmp/vendor-dl + key: vendor-${{ hashFiles('scripts/fetch-vendor.mjs') }} + + - name: Install 7z + run: sudo apt-get update && sudo apt-get install -y p7zip-full + + - name: Fetch vendor (git + gh + gnupg) + run: node scripts/fetch-vendor.mjs + + - name: Package + run: node scripts/pack.mjs + + - name: Upload release assets + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -e + cd releases + ZIP=$(ls github-hanako-*.zip | head -1) + [ -n "$ZIP" ] || { echo "::error::no package zip found in releases/"; exit 1; } + gh release upload "${{ github.ref_name }}" "$ZIP" "$ZIP.sha256" --clobber + + # 单点收尾:资产齐全才留 release,缺则删并 fail(公开 release 不留残缺) + - name: Verify release assets complete + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -e + TAG="${{ github.ref_name }}" + # 资产名 = pkgId + "-v" + version(pack.mjs),version 段带 v 前缀与 tag 一致 + # 如 tag v0.1.1 → github-hanako-v0.1.1.zip(勿用 ${TAG#v} 去 v——曾致误判删 release) + ZIP="github-hanako-$TAG.zip" + if ! gh release view "$TAG" --json assets -q '.assets[].name' | grep -qx "$ZIP"; then + echo "::error::release $TAG missing asset $ZIP" + gh release delete "$TAG" --yes + exit 1 + fi + if ! gh release view "$TAG" --json assets -q '.assets[].name' | grep -qx "$ZIP.sha256"; then + echo "::error::release $TAG missing asset $ZIP.sha256" + gh release delete "$TAG" --yes + exit 1 + fi + echo "release $TAG assets complete: $ZIP + $ZIP.sha256" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 1dd52b8..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,130 +0,0 @@ -# Release — Linux 单平台打包 + 直传 release 资产 -# 骨架对齐 dsh-hanako release.yml(三段式:create-release → build → 资产直传), -# 按 github-hanako 交付物本质裁剪(纯 JS + 内嵌 win 运行时,零 npm 依赖)。 -# -# 触发: push tag v*(发版打 tag 自动触发)或手动 workflow_dispatch -# -# 三段式: -# - create-release(仅 tag 场景): 先建 pre-release(已存在则跳过,--generate-notes) -# - build(needs create-release): ubuntu 单平台 setup-node + fetch-vendor(git/gh/gnupg, -# vendor 走 cache)+ pack(产 zip + sha256);tag 场景直传 release 资产,dispatch 走 artifact -# - verify(仅 tag 场景): 查 release 资产齐全,缺则删 release 并 fail(不留残缺) -# -# 与 dsh-hanako 的差异: -# - 零 npm 依赖(package.json 无 dependencies)→ 无 pnpm install、无 lockfile -# - vendor/ 内嵌 win-x64 运行时(git/gh/gnupg,fetch-vendor.mjs 下载,sha256 校验), -# 交付物平台相关(win 资产)但构建在 ubuntu 单平台完成(纯文件打包,不执行 win 二进制) -# - gnupg 条目解压依赖 7z → build 前 apt 装 p7zip-full -# - 产物目录 releases/(.gitignore 忽略),资产名 github-hanako-v.zip 与 tag 对齐 -name: Release - -on: - push: - tags: ['v*'] - workflow_dispatch: - -jobs: - create-release: - if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - - name: Create pre-release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then - echo "Release ${{ github.ref_name }} already exists, skipping create" - else - gh release create "${{ github.ref_name }}" \ - --prerelease \ - --title "${{ github.ref_name }}" \ - --generate-notes - fi - - build: - needs: create-release - # create-release 仅在 tag 场景运行,dispatch 场景会被 skip;被 needs 的 job skip 会 - # 让下游默认 if(success()) 一起 skip → 用 !cancelled() 显式放行 skipped 依赖链 - # (success(tag) / skipped(dispatch) 都继续构建),保留 failure/cancelled 门禁 - if: ${{ !cancelled() && needs.create-release.result != 'failure' }} - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version: 22 - - # vendor 缓存:key 随 fetch-vendor.mjs(VERSIONS 表)变化,命中则免下载免解压 - - name: Cache vendor - uses: actions/cache@v4 - with: - path: | - vendor - _tmp/vendor-dl - key: vendor-${{ hashFiles('scripts/fetch-vendor.mjs') }} - - - name: Install 7z - run: sudo apt-get update && sudo apt-get install -y p7zip-full - - - name: Fetch vendor (git + gh + gnupg) - run: node scripts/fetch-vendor.mjs - - - name: Package - run: node scripts/pack.mjs - - - name: Upload release assets (tag) - if: startsWith(github.ref, 'refs/tags/v') - shell: bash - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -e - cd releases - ZIP=$(ls github-hanako-*.zip | head -1) - [ -n "$ZIP" ] || { echo "::error::no package zip found in releases/"; exit 1; } - gh release upload "${{ github.ref_name }}" "$ZIP" "$ZIP.sha256" --clobber - - - name: Upload artifacts - uses: actions/upload-artifact@v6 - with: - name: github-hanako-package - retention-days: 3 - path: releases/github-hanako-*.zip* - if-no-files-found: error - - verify: - if: startsWith(github.ref, 'refs/tags/v') - needs: build - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v5 - - name: Verify release assets complete - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -e - TAG="${{ github.ref_name }}" - # 资产名 = pkgId + "-v" + version(pack.mjs),version 段带 v 前缀与 tag 一致 - # 如 tag v0.1.1 → github-hanako-v0.1.1.zip(勿用 ${TAG#v} 去 v——曾致误判删 release) - ZIP="github-hanako-$TAG.zip" - if ! gh release view "$TAG" --json assets -q '.assets[].name' | grep -qx "$ZIP"; then - echo "::error::release $TAG missing asset $ZIP" - gh release delete "$TAG" --yes - exit 1 - fi - if ! gh release view "$TAG" --json assets -q '.assets[].name' | grep -qx "$ZIP.sha256"; then - echo "::error::release $TAG missing asset $ZIP.sha256" - gh release delete "$TAG" --yes - exit 1 - fi - echo "release $TAG assets complete: $ZIP + $ZIP.sha256" From 46e7eb7c2b501c0f99c4edbf3988abf866235cce Mon Sep 17 00:00:00 2001 From: ProjectNyaser <61904116+ProjectNyaser@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:11:52 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix(ci):=20=E9=87=87=E7=BA=B3=20CodeRabbit?= =?UTF-8?q?=20=E4=B8=A4=E6=9D=A1=E2=80=94=E2=80=94release=20=E9=99=90?= =?UTF-8?q?=E7=9C=9F=E5=AE=9E=20tag=20push=20+=20=E6=89=93=E5=8C=85?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E5=90=8E=E6=89=8D=E5=BB=BA=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. release job if 补 github.event_name == 'push':dispatch 手动触发可指 tag ref,原条件会误跑 release 覆盖正式 release 资产。 2. Create release 移到 Package 之后:原顺序打包失败会留下无资产的空 release(verify 被跳过救不了);现在打包成功才建 release。 Co-authored-by: HanaAgent <313794804+HanaAgent@users.noreply.github.com> --- .github/workflows/ci.yml | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bc7b02..dec1f74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,7 +90,8 @@ jobs: # ---- tag:完整发版链(打包唯一发生点,不再与 CI 重复) ---- release: - if: ${{ startsWith(github.ref, 'refs/tags/v') }} + # 仅真实 tag push 触发(dispatch 可指 tag ref,会误覆盖 release 资产 → 排除) + if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} needs: check runs-on: ubuntu-latest permissions: @@ -103,20 +104,6 @@ jobs: with: node-version: 22 - # 先建 release(pre-release,不占 latest;已存在跳过) - - name: Create release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then - echo "Release ${{ github.ref_name }} already exists, skipping create" - else - gh release create "${{ github.ref_name }}" \ - --prerelease \ - --title "${{ github.ref_name }}" \ - --generate-notes - fi - - name: Cache vendor uses: actions/cache@v4 with: @@ -134,6 +121,20 @@ jobs: - name: Package run: node scripts/pack.mjs + # 打包成功才建 release(避免打包失败留下无资产的空 release);已存在则跳过 + - name: Create release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then + echo "Release ${{ github.ref_name }} already exists, skipping create" + else + gh release create "${{ github.ref_name }}" \ + --prerelease \ + --title "${{ github.ref_name }}" \ + --generate-notes + fi + - name: Upload release assets shell: bash env: From 5671f442e75a4762a37a87f3bde13f074a872e6c Mon Sep 17 00:00:00 2001 From: ProjectNyaser <61904116+ProjectNyaser@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:17:03 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix(ci):=20=E9=87=87=E7=BA=B3=20CodeRabbit?= =?UTF-8?q?=20=E4=B8=89=E8=BD=AE=E4=B8=A4=E6=9D=A1=E2=80=94=E2=80=94upload?= =?UTF-8?q?=20=E5=A4=B1=E8=B4=A5=E5=85=9C=E5=BA=95=E6=B8=85=E7=90=86=20+?= =?UTF-8?q?=20ref=5Fname=20=E6=B3=A8=E5=85=A5=E9=9D=A2=E6=94=B6=E6=95=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Verify step 加 !cancelled():upload 失败(set -e 中断)也会执行资产检查并 清理残缺 release;release 未建(package/fetch 失败在 create 前)→ 无残缺 正常退出不误报。 2. github.ref_name 防注入:tag 名允许引号/分号等字符,直接拼 shell 字符串 可被引号破坏注入 → 三处(Create/Upload/Verify)改经 env TAG 传入, 脚本内 "$TAG" 双引号引用。 Co-authored-by: HanaAgent <313794804+HanaAgent@users.noreply.github.com> --- .github/workflows/ci.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dec1f74..a3db9d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,17 +121,19 @@ jobs: - name: Package run: node scripts/pack.mjs - # 打包成功才建 release(避免打包失败留下无资产的空 release);已存在则跳过 + # 打包成功才建 release(避免打包失败留下无资产的空 release);已存在则跳过。 + # TAG 经 env 传入(github.ref_name 可含引号/分号等字符,直接拼 shell 有注入面) - name: Create release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ github.ref_name }} run: | - if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then - echo "Release ${{ github.ref_name }} already exists, skipping create" + if gh release view "$TAG" >/dev/null 2>&1; then + echo "Release $TAG already exists, skipping create" else - gh release create "${{ github.ref_name }}" \ + gh release create "$TAG" \ --prerelease \ - --title "${{ github.ref_name }}" \ + --title "$TAG" \ --generate-notes fi @@ -139,20 +141,28 @@ jobs: shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ github.ref_name }} run: | set -e cd releases ZIP=$(ls github-hanako-*.zip | head -1) [ -n "$ZIP" ] || { echo "::error::no package zip found in releases/"; exit 1; } - gh release upload "${{ github.ref_name }}" "$ZIP" "$ZIP.sha256" --clobber + gh release upload "$TAG" "$ZIP" "$ZIP.sha256" --clobber - # 单点收尾:资产齐全才留 release,缺则删并 fail(公开 release 不留残缺) + # 单点收尾:资产齐全才留 release,缺则删并 fail(公开 release 不留残缺)。 + # !cancelled() 兜底:upload 失败(set -e 中断)也会执行清理;release 未建 + # (package/fetch 失败发生在 create 前)→ 无残缺,正常退出不误报 - name: Verify release assets complete + if: ${{ !cancelled() }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ github.ref_name }} run: | set -e - TAG="${{ github.ref_name }}" + if ! gh release view "$TAG" >/dev/null 2>&1; then + echo "release $TAG 不存在(此前步骤未建 release),无需清理" + exit 0 + fi # 资产名 = pkgId + "-v" + version(pack.mjs),version 段带 v 前缀与 tag 一致 # 如 tag v0.1.1 → github-hanako-v0.1.1.zip(勿用 ${TAG#v} 去 v——曾致误判删 release) ZIP="github-hanako-$TAG.zip" From 962864dd9b933d074ce7a51a9607d6b58cfddc51 Mon Sep 17 00:00:00 2001 From: ProjectNyaser <61904116+ProjectNyaser@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:23:27 +0800 Subject: [PATCH 4/5] =?UTF-8?q?fix(ci):=20=E9=87=87=E7=BA=B3=20CodeRabbit?= =?UTF-8?q?=20=E5=9B=9B=E8=BD=AE=E4=B8=A4=E6=9D=A1=E2=80=94=E2=80=94tag/ma?= =?UTF-8?q?nifest=20=E4=B8=80=E8=87=B4=E6=80=A7=E6=A0=A1=E9=AA=8C=20+=20vi?= =?UTF-8?q?ew=20=E9=94=99=E8=AF=AF=20propagate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. release job 加 Validate tag step(Create release 前 fail-fast):pack 产物名 来自 manifest、verify 按 tag 期待资产名,tag 与 manifest version 不一致会 在 verify 误删 release——先校验(v == ref_name)。 2. verify 的 no-op 路径改判 Create release step outcome(steps.create.outcome != success → 无残缺退出 0),不再用 gh release view 失败判不存在——create 成功后 release 必存在,view 报错 = API 错误 propagate fail(原逻辑吞错误 会留残缺)。 Co-authored-by: HanaAgent <313794804+HanaAgent@users.noreply.github.com> --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3db9d4..a427330 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,6 +104,21 @@ jobs: with: node-version: 22 + # tag 与 manifest version 一致性校验:pack 产物名来自 manifest,verify 按 tag 期待 + # 资产名——tag/manifest 不一致会在 verify 误删 release,这里 fail-fast + - name: Validate tag matches manifest version + env: + TAG: ${{ github.ref_name }} + run: | + set -e + VER=$(node -p "require('./manifest.json').version") + EXPECT="v$VER" + if [ "$TAG" != "$EXPECT" ]; then + echo "::error::tag $TAG 与 manifest version $VER 不一致(应为 $EXPECT)" + exit 1 + fi + echo "tag $TAG matches manifest version $VER" + - name: Cache vendor uses: actions/cache@v4 with: @@ -124,6 +139,7 @@ jobs: # 打包成功才建 release(避免打包失败留下无资产的空 release);已存在则跳过。 # TAG 经 env 传入(github.ref_name 可含引号/分号等字符,直接拼 shell 有注入面) - name: Create release + id: create env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: ${{ github.ref_name }} @@ -159,10 +175,16 @@ jobs: TAG: ${{ github.ref_name }} run: | set -e - if ! gh release view "$TAG" >/dev/null 2>&1; then - echo "release $TAG 不存在(此前步骤未建 release),无需清理" + # Create release 未执行成功(fetch/package 失败在 create 前)→ 无 release 需清理 + if [ "${{ steps.create.outcome }}" != "success" ]; then + echo "create-release 未执行(此前步骤失败),无残缺 release" exit 0 fi + # create 成功则 release 必存在;view 失败 = API 错误,propagate(不误判不存在) + if ! gh release view "$TAG" >/dev/null 2>&1; then + echo "::error::release $TAG 查询失败(create 已成功但 view 报错)" + exit 1 + fi # 资产名 = pkgId + "-v" + version(pack.mjs),version 段带 v 前缀与 tag 一致 # 如 tag v0.1.1 → github-hanako-v0.1.1.zip(勿用 ${TAG#v} 去 v——曾致误判删 release) ZIP="github-hanako-$TAG.zip" From c70faf44cb73afbe5f48e9d6cf3a4a7a734788c2 Mon Sep 17 00:00:00 2001 From: ProjectNyaser <61904116+ProjectNyaser@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:29:31 +0800 Subject: [PATCH 5/5] =?UTF-8?q?fix(ci):=20=E9=87=87=E7=BA=B3=20CodeRabbit?= =?UTF-8?q?=20=E4=BA=94=E8=BD=AE=E2=80=94=E2=80=94create=20failure=20?= =?UTF-8?q?=E4=B9=9F=E6=9F=A5=E8=AF=81=E6=B8=85=E7=90=86=E5=8D=8A=E5=BB=BA?= =?UTF-8?q?=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh release create 内部是 draft→upload→publish 多步,中途失败会留下半建 release。verify 原逻辑把 create outcome=failure 也当"无残缺"跳过 → 改: 仅 skipped(create 未执行)才跳过;success/failure 均查证 release 存在性, 用 gh api 404 精确区分「不存在」(无半成品,退出 0)与「API 错误」 (propagate fail),半建 release 落入后续资产检查被清理。 Co-authored-by: HanaAgent <313794804+HanaAgent@users.noreply.github.com> --- .github/workflows/ci.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a427330..0388f28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -175,14 +175,21 @@ jobs: TAG: ${{ github.ref_name }} run: | set -e - # Create release 未执行成功(fetch/package 失败在 create 前)→ 无 release 需清理 - if [ "${{ steps.create.outcome }}" != "success" ]; then + # 仅 create-release 被跳过(fetch/package 失败在 create 前)→ 确定无 release + if [ "${{ steps.create.outcome }}" == "skipped" ]; then echo "create-release 未执行(此前步骤失败),无残缺 release" exit 0 fi - # create 成功则 release 必存在;view 失败 = API 错误,propagate(不误判不存在) - if ! gh release view "$TAG" >/dev/null 2>&1; then - echo "::error::release $TAG 查询失败(create 已成功但 view 报错)" + # create success / failure 均查证:success 后必存在;failure 可能半建 + # (gh release create 是 draft→upload→publish 多步,中途失败留孤儿) + # 用 gh api 404 精确区分「不存在」与「API 错误」,错误 propagate + if ! gh api "repos/{owner}/{repo}/releases/tags/$TAG" >/dev/null 2>&1; then + MSG=$(gh api "repos/{owner}/{repo}/releases/tags/$TAG" 2>&1 >/dev/null || true) + if echo "$MSG" | grep -qi 'not found'; then + echo "release $TAG 不存在(create 未留下半成品),无需清理" + exit 0 + fi + echo "::error::release $TAG 查询失败(outcome=${{ steps.create.outcome }}):$MSG" exit 1 fi # 资产名 = pkgId + "-v" + version(pack.mjs),version 段带 v 前缀与 tag 一致