# Fork 发布与发布后核对 本文件是 `slark-dsh-cicd` 的操作附件:需要**无上游写权限发布**,或需要**逐项核对远端资产**时读取。 把它当模板:替换 `<...>` 占位符,按阶段执行,每阶段的核验不通过就停下,不要"带病"推进。 ## 0. 变量与前置 ```bash export HOME="/Users/johnq" export PATH="/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin:/opt/homebrew/bin:$PATH" UP=/ # 例如 Aisland-SJL/dsh-worktable(外部作者,无写权限) ME= # 例如 qiudl PKG=/01_content # 打包脚本所在目录 VER=0.4.1 # = package.json#version ``` ```bash gh auth status ssh -T git@github.com 2>&1 | head -3 gh api "repos/$UP" --jq '.permissions' # push:false → 必须走 fork 发布 git remote -v ``` ## 1. 改指向 → 重新打包(顺序不可颠倒) ```bash cd "$PKG" grep -rn "" .. --include='*.json' --include='*.ts' --include='*.tsx' --include='*.md' --include='*.mjs' # 逐处改完只后再打包: npm run check && npm run test:gate && npm run pack shasum -a 256 dist/v$VER/*.tgz TMP=$(mktemp -d) && tar -xzf dist/v$VER/dsh-worktable.tgz -C "$TMP" grep -rn "" "$TMP" ; echo "grep exit=$? (1 = 无残留,正确)" ``` 判据:`check`/`test:gate`/`pack` 全部 exit 0;两个 tgz 同 sha;解包无旧仓库名。 ## 2. fork 与干净发布分支 ```bash cd gh repo fork "$UP" --clone=false # 已存在会提示 already exists,可复用 git remote add fork "git@github.com:$ME/.git" # 已存在:git remote set-url fork … git fetch --no-tags origin main OURS=$(git rev-parse HEAD) # 本地"发布内容已就绪"的 HEAD git diff --name-status origin/main "$OURS" | awk '$1 ~ /^[DR]/' # 期望空;有 D/R 先处理再用 gate git checkout -B release/v$VER origin/main git rm -rq --cached . git checkout "$OURS" -- . git add -A git commit -m "release: v$VER(REQ-…)<一句话说明>" DIFFOUT="$(git diff --stat "$OURS")" if [ -n "$DIFFOUT" ]; then echo "GATE FAILED:"; echo "$DIFFOUT" git checkout <原分支> && git branch -D release/v$VER # abort:不留半成品分支 exit 1 fi echo "GATE PASSED: release tree == OURS tree" ``` ## 3. 推送(只对 fork)与 draft Release ```bash git push -u fork release/v$VER git tag -f v$VER && git push -f fork v$VER # -f 仅限自己 fork 的 tag gh release create v$VER \ dist/v$VER/dsh-worktable.tgz dist/v$VER/dsh-worktable-$VER.tgz \ --repo "$ME/" --draft --title " v$VER" --notes-file /tmp/rel-notes.md ``` 原仓库零改动复核: ```bash git ls-remote "git@github.com:$UP.git" # 无 release/v… 分支、无新 tag gh release list --repo "$UP" # 与发布前一致 ``` ### Release notes 模板(draft 阶段就写全新值) ```markdown # v > 发布方:fork /(原仓库 为上游来源)。插件内更新检查已指向本 fork。 ## 新增 / 修复 / 清理 ## 验证 - check / gate / pack 实际输出(测试条数、断言项) - 双资产同 SHA: - 解包 grep 无旧仓库名 - 发布分支为干净单提交(父提交 = 上游 main),`git diff --stat ` 为空 ## 安装 网页端 / 桌面端一行命令(指向 fork) ## 已知边界 - draft 期间 releases/latest 仍指旧版 → 更新检查看不到新版 - 保留的第三方外链、平台未验证范围 ``` ## 4. publish 与发布后核对矩阵 ```bash gh release edit v$VER --repo "$ME/" --draft=false ``` | 核对项 | 命令 | 通过判据 | | --- | --- | --- | | 资产列表与 digest | `gh release view v$VER --repo $ME/ --json assets` | 两个资产 `digest` = 本地 sha | | 下载后 sha | `gh release download v$VER --repo $ME/ --dir "$D"` + `shasum -a 256 "$D"/*.tgz` | 与本地逐字一致 | | 与本地验收件一致 | `cmp "$D/dsh-worktable.tgz" dist/v$VER/dsh-worktable.tgz` | 无差异(byte-identical) | | 包内无旧仓库名 | 解包后 `grep -rn ""` | 无输出(exit 1) | | 包内版本 = tag | 解包读 `package.json#version` | `v$VER` | | 匿名可下载 | `curl -sL -o /dev/null -w '%{http_code}\n' <资产 URL>` | publish 后 200/302;draft 期 404 属预期 | | 安装可用 | 临时目录 `npm install ` + `import()` 断言 | 导出/版本断言通过 | - **`verify-remote.mjs` 的平台限制**:其下载走 `powershell Invoke-WebRequest`,只在 Windows 可用; 在 macOS 会 `FAIL: download fixed-name asset`。此时用上表的 `gh release view/download` + `shasum` + `cmp` 等价替代, 并说明该脚本的 GET URL 已证明改指生效。 - **"检查更新"看不到新版**的排查顺序:Release 是否 draft → `releases/latest` 指向 → 插件内 `UPDATE_REPO` 指向 → `latest` 资产名与代码拼法一致。 ## 5. 链路判死模板(macOS 无 `timeout`) ```bash ( git fetch --no-tags origin main ) & PID=$! for i in $(seq 1 30); do sleep 1; kill -0 "$PID" 2>/dev/null || break; done if kill -0 "$PID" 2>/dev/null; then kill -9 "$PID"; pkill -9 -f git-upload-pack; echo "TIMEOUT(30s)"; fi ``` - HTTPS 到 GitHub `curl` 返回 `000` → 整体不通,改 SSH(`git remote set-url`)。 - 30 秒内 `fatal: early EOF` → 链路被掐断;记录原文与时间,换网络/协议重试。 - 认证或网络失败时不做破坏性重试,也不要把 force 用到上游;保留本地提交并上报失败原文。