mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 06:47:29 +00:00
fix(ci): gitcode 目标仓前置检查加有界重试(网络抖动不再误判)
2026-10-21 的 main 流水线(dfc4e16)里,「前置检查 gitcode 目标仓是否存在」 首次执行时 gitcode 没有给出预期响应,一次 ls-remote 判失败 ⇒ sync job 红; 重跑立刻全绿。把一次网络抖动翻译成「镜像同步坏了」,是纯噪声。 改法:只对**网络层**失败重试,其余立即失败。 - 网络层(DNS/连接重置/TLS/超时/EOF)→ 最多 3 次,退避 5s、10s - 仓不存在(gitcode 实测:could not be found + **403**,不是 404) → 立即失败,不重试。重试只会把「去建仓」拖成十几秒空等 - 凭据问题(401/403 但不带 not-found 特征)→ 立即失败,不重试 (token 错了等 15 秒也不会变对) - 分类顺序上 notfound 必须先于 403:gitcode 的「仓不存在」响应里 **同时**含 could not be found 与 error: 403,先判 403 会把真问题贴上 「凭据问题」的错误标签 - 每次尝试打一行「第 N/M 次探测失败(类别):摘要」;重试提示打到 stderr (⏳ … 秒后重试),Actions 日志里一眼看得出发生过重试 - 耗尽重试时整段回放每次尝试的摘要,并明确写「判定:网络问题」 —— 与「仓不存在」/「凭据问题」的判定措辞互不相同,可直接 grep 区分 同口径:**抽成 .github/scripts/check-gitcode-repo.sh,两个 workflow 共用同一个 文件**,而不是两边各写一份「逐字一致」的脚本 —— 后者迟早会漂。ci.yml 的 sync-gitcode-main 与 release.yml 的 sync-gitcode 各留 1 行 bash 调用。 (抽得出公共片段,故没有采用「两边逐字改」的方案。) token 安全:GC_URL 含 token,永不 echo;所有输出先过 redact()。脱敏两道: 先按字面量遮 token(BRE 元字符先转义),再按 URL 结构遮 userinfo@。 结构式的 password 段**不能排除 `/`** —— 真实 token 可以含 `/`,第一版写成 [^@/[:space:]]* 时 `https://user:tok/en@host` 匹配不上,只剩字面量一道兜住 (判据 C6 首次就是红的)。 判据与变异(9 组正向 / 8 条变异,全部咬住): 判据脚本与变异脚本见 commondev 台账 criteria/b7-gitcode-precheck-retry{,.mutations}.sh。 正向覆盖:重试次数上限(恰好 3 次探测)、仓不存在时 1 次即失败无重试痕迹、 首次成功无重试噪声、抖动后第 2 次成功、凭据问题不重试、token 不进日志、 默认退避真的是 5s/10s(用假 sleep 记录入参,不真等 15 秒)、 两处 workflow 都调同一脚本事 yaml 可解析 + bash -n。 变异 8/8 咬住:默认次数 3→1、退避→0、仓不存在也重试、去掉上限、 去掉重试提示、清空 notfound 特征串、去掉结构式脱敏、ci.yml 退回内联 ls-remote。 过程中修掉三处自己判据的盲区(都不是改产物去迁就判据,而是补判据): 1. M2(退避→0/0)首次未被咬住 ⇒ 补 C7「默认退避 = 5 10」(假 sleep 记录入参) 2. M7(删结构式脱敏)首次未被咬住 ⇒ 补 C7b:userinfo 密码用**别的** secret 且**含 `/`**。C6 用当前 token 的字面量做输入,字面量替换本身就能抹掉, 于是结构式规则删了也照样绿;且密码不含 `/` 时兜底的裸 user@ 规则会顶上, 同样验不出来 3. C7b 第一版断言 grep 'JianFeeeee' 会误报 —— 脚本正常输出里就有 gitcode.com/JianFeeeee/HologramAgent(那是路径不是凭据),改为断言 userinfo 形态(://JianFeeeee[:@]) 真实网络实测(不是只跑假 git): - 仓存在:目标仓可访问,rc=0 - 仓不存在:1 次探测即失败,日志含 could not be found + 403,rc=1 - 网络失败:3 次探测 + 2 次退避,总耗时 5.7s(退避调成 1s/1s),rc=1 yaml.safe_load 三个 workflow 全部可解析;bash -n 通过。 未改动(留待裁决):deploy/scripts/upload_assets.py docstring 里 「SDK 仓传 JianFeeeee/homeagent-sdk」指 gitcode 侧、与实测一致 (gitcode: homeagent-sdk=200 / homeagentsdk=404;GitHub 相反),保持原样。
This commit is contained in:
48
.github/workflows/ci.yml
vendored
48
.github/workflows/ci.yml
vendored
@ -246,48 +246,24 @@ jobs:
|
||||
# 若不在这里显式探测,缺少目标仓时只会得到 git 的原始报错
|
||||
# ("repository not found" 混在 push 输出里),看不出是「仓没建」。
|
||||
# 语义:token 未配置 = 可选项跳过(上面那步);token 有但仓不存在 = 硬失败。
|
||||
#
|
||||
# ★ 有界重试(2026-10-21 dfc4e16 的教训):首次跑这一步时 gitcode 网络抖动,
|
||||
# 一次 ls-remote 判失败 ⇒ job 红;重跑立刻全绿。现在只对**网络层**失败
|
||||
# 重试(3 次,退避 5s/10s),而「仓不存在」与「凭据问题」**立即失败不重试**
|
||||
# —— 后两者重试只会把真问题拖长、并把它埋在噪声里。
|
||||
#
|
||||
# 实现落在 .github/scripts/check-gitcode-repo.sh,与 release.yml 的
|
||||
# sync-gitcode **共用同一个文件**(同口径靠同一份代码保证,不靠人抄两遍)。
|
||||
- name: 前置检查 gitcode 目标仓是否存在
|
||||
if: steps.tok.outputs.ok == 'true'
|
||||
env:
|
||||
GC_TOKEN: ${{ secrets.GITCODE_TOKEN }}
|
||||
# 显式传环境变量(而不是 shell 局部变量):脚本的默认值与这里
|
||||
# 相同,但写在 env 里才是**真的传下去**,改仓名时不用改两处逻辑。
|
||||
GC_REPO: JianFeeeee/HologramAgent
|
||||
run: |
|
||||
set -euo pipefail
|
||||
GC_URL="https://JianFeeeee:${GC_TOKEN}@gitcode.com"
|
||||
GC_REPO="JianFeeeee/HologramAgent"
|
||||
# 用 ls-remote 探测:与后面那次 push 走同一个 URL、同一套凭据,
|
||||
# 比另调一次 API 更贴近真实失败面。
|
||||
if out=$(GIT_TERMINAL_PROMPT=0 git ls-remote --heads \
|
||||
"${GC_URL}/${GC_REPO}.git" 2>&1); then
|
||||
echo " 目标仓可访问:gitcode.com/${GC_REPO}"
|
||||
else
|
||||
# 日志脱敏:git 报错可能把 URL 的 userinfo(token 就在里面)带出来。
|
||||
# 先按 URL 结构遮 https://<userinfo>@ —— 与 token 内容无关,稳;
|
||||
# 再尽力遮一次字面量(token 含特殊字符时可能不生效,故只做兜底)。
|
||||
err=$(printf '%s\n' "$out" | sed -E 's#(https?://)[^@/[:space:]]*@#\1***@#g')
|
||||
err=$(printf '%s\n' "$err" | sed "s|${GC_TOKEN}|***|g" 2>/dev/null || printf '%s\n' "$err")
|
||||
case "$err" in
|
||||
# gitcode 真实报错(2026-10 实测):目标仓不存在时返回
|
||||
# remote: <CH.00905403> The project you were looking for could not be found.
|
||||
# fatal: ... The requested URL returned error: 403
|
||||
# 注意是 "could not be found" 与 403,不是 github 那种 "Repository not found"/404。
|
||||
*"could not be found"*|*"not found"*|*"Not Found"*|*"404"*|*"does not exist"*|*"does not appear to be a git repository"*)
|
||||
echo " ✗ gitcode 目标仓不存在:gitcode.com/${GC_REPO}"
|
||||
echo " 请先在该账号下创建镜像仓(只读镜像),再重跑本 job:"
|
||||
echo " https://gitcode.com/${GC_REPO}"
|
||||
;;
|
||||
*"403"*|*"401"*|*"Forbidden"*|*"Unauthorized"*)
|
||||
echo " ✗ 无法访问 gitcode 目标仓 gitcode.com/${GC_REPO}:仓不存在,或 token 无权访问"
|
||||
echo " 若仓已建,请确认 GITCODE_TOKEN 属于该仓的推送账号:"
|
||||
echo " https://gitcode.com/${GC_REPO}"
|
||||
;;
|
||||
*)
|
||||
echo " ✗ 无法访问 gitcode 目标仓 gitcode.com/${GC_REPO}(网络或凭据问题):"
|
||||
printf '%s\n' "$err" | sed 's/^/ /'
|
||||
;;
|
||||
esac
|
||||
# 显式失败 —— 不静默跳过,也不 echo 一句就当成功。
|
||||
exit 1
|
||||
fi
|
||||
bash .github/scripts/check-gitcode-repo.sh
|
||||
- name: 推 main 到 gitcode(快进)
|
||||
if: steps.tok.outputs.ok == 'true'
|
||||
env:
|
||||
|
||||
Reference in New Issue
Block a user