mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 14:57:38 +00:00
gitcode 侧镜像仓已完成改名,旧名 HomeAgent 变成 301 跳转,真仓是
HologramAgent。dbb787a 里三处 GC_REPO 定义点仍取旧名(命中 301),本批只
改取值与说明,**不改变 dbb787a 已建立的「每个文件恰一个定义点」结构**,
不引入任何新字面量。
实测(2026-10-21 20:1x,直连不带代理,非推测):
$ curl -s -o /dev/null -w '%{http_code}' https://gitcode.com/JianFeeeee/<repo>
HologramAgent → 200 ← 当前取值
HomeAgent → 301 ← 旧名,跳转到 HologramAgent
homeagent-sdk → 200(SDK 仓,另一对象)
hologramagentsdk → 200(SDK 仓,另一对象)
homeagentsdk → 404
HologramAgent-sdk → 404
「301 不是另一个仓,就是同一仓改名」的判定依据:两个地址 `git ls-remote`
得到的 refs 列表 md5 相同(同一组分支与 SHA),且 curl 页面 title 一致。
三个定义点(各文件恰好 1 处,消费点全部走变量,本次只改这三行的取值):
1. .github/workflows/ci.yml job sync-gitcode-main 的 env.GC_REPO
2. .github/workflows/release.yml job sync-gitcode 的 env.GC_REPO
3. deploy/scripts/upload_assets.py 的 os.environ.get("GITCODE_REPO", ...) 默认值
消费点未动:ci.yml 2 处、release.yml 4 处命令行,仍全部是 ${GC_REPO}。
注释同步改准(原来把 301 的仓写成「200 ← 当前用这个」,是错的):
- 两个 workflow 的取值依据清单换成上面六个仓的现状,注明实测时间与 curl 命令
- 明确 HomeAgent = 301 跳转、HologramAgent = 当前取值
- 「以后再改名只改这三行」的说明保留
docs/zh/ci-cd-runbook.md 同步:
- 总览表 gitcode 镜像改为 HologramAgent(与主仓同名)
- 「当前取值」段与六仓实测表、301 判定依据
- API 侧口径也改准:/api/v5/repos/JianFeeeee/{HomeAgent,HologramAgent}
不带 token 均 400(需鉴权,非仓不存在);/releases/tags/v1.3.13
两名字均 200 且响应体一致。旧文档写「HologramAgent→404 是死链」已不成立。
- §3.3 curl 验活地址、§3.4 手工上传示例的 GITCODE_REPO 同步为新值
判据(正向 14 项 + 变异 11 条,全部实跑):
- 两个 workflow yaml.safe_load 解析通过;每个 env.GC_REPO 恰好 1 处
- 三处定义点取值完全一致(P4);消费点计数 ci=2/release=4(P6)
- P8 改为「不带 -L 的 200」:这正是本次误判的根因——之前用 curl -L 测,
301 跟随后也是 200,把「旧名跳转」误读成「旧名是真仓、新名 404」
- 变异 M11「三处一致改回旧名 HomeAgent」只被 P8 抓住(P4 仍绿),
证明该判据能单独区分「一致但指向 301 旧名」
- 所有 step run 块过 bash -n(30 个 run 块,0 错)
- gitcode 作 import host 残留 0;工作区无 .go/.lua/go.mod/go.sum 变更
零代码改动:packaging_test.go 里「禁止历史模块路径」的反向断言未动,
third_party 未动,systemd 相关行未动。
336 lines
15 KiB
YAML
336 lines
15 KiB
YAML
# HomeAgent 主仓 CI。
|
||
#
|
||
# 设计原则:**CI 里跑的每一条命令,都是本地已实测通过的命令**。
|
||
# 不写「应该有用来试试」的步骤 —— 未验证的 CI 步骤会把假红灯变成常态,
|
||
# 最后所有人学会忽略它。
|
||
#
|
||
# 覆盖范围与本地 `make test` 对齐(build / vet / test / client-versions /
|
||
# gui / csrc),并按依赖拆成独立 job,便于失败定位。
|
||
#
|
||
# 明确**不在** CI 里跑的东西(依赖真机/密钥/内网,跑了只会变 flaky 噪音):
|
||
# - deploy-*.sh / homed 生产部署
|
||
# - waiter 真机验证(192.168.2.x)
|
||
# - cmd/gui 的 `npm run test-live`(需真 Electron + Xvfb + 真后端)
|
||
# - scripts/kernel-stress/*(需 llmsproxy 与压测端点)
|
||
# - 需要 DEEPSEEK_API_KEY / MEDIALIVE_* 的真实 LLM 测试(已自带 t.Skip)
|
||
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches: [main, 'release/**']
|
||
pull_request:
|
||
workflow_dispatch:
|
||
|
||
# 只读权限:CI 不需要写仓库。
|
||
permissions:
|
||
contents: read
|
||
|
||
# 同一分支连续推送时取消旧跑,省额度也避免过期结果误导。
|
||
concurrency:
|
||
group: ci-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
env:
|
||
# gojieba / onnx 相关包需要 cgo ⇒ 不能用 CGO_ENABLED=0。
|
||
CGO_ENABLED: 1
|
||
# 减少 go test 输出噪音。
|
||
GOFLAGS: -buildvcs=false
|
||
|
||
jobs:
|
||
# ── Go 后端:构建 + 静态检查 + 全量测试 + 跨平台客户端版本一致性 ──
|
||
go:
|
||
name: Go build / vet / test
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 30
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version-file: go.mod
|
||
cache: true
|
||
|
||
# cgo 需要 gcc/g++(gojieba 会编译自带 C++ 源码)。
|
||
- name: 确认 cgo 工具链
|
||
run: |
|
||
gcc --version | head -1
|
||
g++ --version | head -1
|
||
|
||
- name: go build ./...
|
||
run: go build ./...
|
||
|
||
- name: go vet ./...
|
||
run: go vet ./...
|
||
|
||
# ./... 不点名 cmd/gui(该目录是纯 Electron,无 .go 文件):
|
||
# 显式 `go test ./cmd/gui` 会报 "no Go files",那是误报,不是缺陷。
|
||
- name: go test ./...
|
||
run: go test ./... -count=1 -timeout 20m
|
||
|
||
# 跨平台客户端版本一致性:内核 internal/meta 是唯一事实源,
|
||
# GUI(package.json) / 鸿蒙(AppScope/app.json5) / waiter 都必须跟它一致。
|
||
- name: 客户端版本一致性
|
||
run: make check-client-versions
|
||
|
||
# ── 竞态检测(并发改动的主要防线)──
|
||
race:
|
||
name: Race detector
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 20
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version-file: go.mod
|
||
cache: true
|
||
- name: go test -race(并发核心)
|
||
run: |
|
||
go test -race \
|
||
./internal/agent/core/ ./cmd/waiter/ \
|
||
-count=1 -timeout 15m
|
||
|
||
# ── 交叉编译:可在无 cgo 下构建的客户端/工具 ──
|
||
#
|
||
# 只有这三个 cmd 支持纯交叉编译。另外三个依赖 cgo(gojieba / onnx):
|
||
# homed / memgc / homed-kb-migrate → internal/memory(gojieba)
|
||
# homed → internal/agent/api(onnx)
|
||
# 它们必须在原生平台构建(见 Makefile 的 build target)。
|
||
cross:
|
||
name: Cross-compile
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 20
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
include:
|
||
- goos: linux
|
||
goarch: amd64
|
||
ext: ""
|
||
- goos: linux
|
||
goarch: arm64
|
||
ext: ""
|
||
- goos: darwin
|
||
goarch: amd64
|
||
ext: ""
|
||
- goos: darwin
|
||
goarch: arm64
|
||
ext: ""
|
||
- goos: windows
|
||
goarch: amd64
|
||
ext: ".exe"
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version-file: go.mod
|
||
cache: true
|
||
- name: 构建 ${{ matrix.goos }}/${{ matrix.goarch }}
|
||
env:
|
||
GOOS: ${{ matrix.goos }}
|
||
GOARCH: ${{ matrix.goarch }}
|
||
CGO_ENABLED: 0
|
||
run: |
|
||
set -euo pipefail
|
||
mkdir -p dist
|
||
for c in waiter initconfig mock-server; do
|
||
out="dist/${c}_${{ matrix.goos }}_${{ matrix.goarch }}${{ matrix.ext }}"
|
||
go build -trimpath -o "$out" "./cmd/${c}"
|
||
echo " ✓ ${c} ${{ matrix.goos }}/${{ matrix.goarch }}"
|
||
done
|
||
|
||
# ── Electron GUI(纯 Node 测试,零依赖)──
|
||
#
|
||
# `npm test` 跑五个 .mjs,全部只 import node: 内置模块(fs/url/path/vm),
|
||
# 所以**不需要 npm ci、不需要 electron**,秒级完成。
|
||
# `npm run test-live` 需真 Electron + 真后端 ⇒ 不进 CI。
|
||
#
|
||
# endpoint-align.test.mjs 跨出 cmd/gui 读 ../../internal/plugins/webui/handler.go
|
||
# 做端点对账 —— checkout 深度足够(默认 fetch-depth:1 已含工作树文件),
|
||
# 不需要额外 checkout 步骤。
|
||
#
|
||
# connections-io.test.mjs 同样是沙箱里跑 main.js 的**真实函数**(node:vm),
|
||
# 在临时目录里断言连接配置的加载/保存行为,不碰真实用户数据。
|
||
gui:
|
||
name: GUI (node)
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 10
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
- uses: actions/setup-node@v7
|
||
with:
|
||
node-version: '22'
|
||
- name: npm test
|
||
working-directory: cmd/gui
|
||
run: npm test
|
||
|
||
# ── C 基础设施门禁(ABI / 告警 / ASan+UBSan / 跨架构)──
|
||
csrc:
|
||
name: C infrastructure gates
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 20
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
|
||
# clang 供双编译器告警对照;gcc-aarch64 供跨架构编译门禁。
|
||
# 门禁在缺工具时是显式 SKIP 而不是假通过,这里装齐以免静默降级。
|
||
- name: 安装 C 工具链
|
||
run: |
|
||
sudo apt-get update -qq
|
||
sudo apt-get install -y -qq cmake clang gcc-aarch64-linux-gnu
|
||
|
||
- name: make check-csrc
|
||
run: make check-csrc
|
||
|
||
# ── 文档站构建(mkdocs,纯 Python,无外部依赖)──
|
||
docs:
|
||
name: Docs build
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 10
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
- uses: actions/setup-python@v7
|
||
with:
|
||
python-version: '3.12'
|
||
- name: 校验站点配置可解析
|
||
# 这里只做「配置与文档源没坏」的轻量校验,不做完整 mkdocs build
|
||
# (站点发布有独立流水线,见 deploy/scripts/deploy-sdk-site.sh)。
|
||
run: |
|
||
set -euo pipefail
|
||
if [ -f mkdocs.yml ]; then
|
||
python -c \
|
||
"import yaml; yaml.safe_load(open('mkdocs.yml'))" \
|
||
&& echo "mkdocs.yml OK"
|
||
else
|
||
echo "无 mkdocs.yml,跳过"
|
||
fi
|
||
test -d docs || echo "无 docs/,跳过"
|
||
|
||
# ── gitcode 镜像同步(main 分支)──
|
||
#
|
||
# 背景(2026-10-06 审计):gitcode 的定位是**只读镜像**(ci-cd-runbook §0),
|
||
# 但既有 sync job 只在 release.yml 里推 **tag** —— main 分支从不同步,
|
||
# 导致镜像的 main 停在 09-29、与主仓分叉 768/746(当时已 force push 对齐一次)。
|
||
#
|
||
# 本 job 把「镜像 = 主仓」交给 CI 保证:main 每次推送且**全部必需检查通过后**
|
||
# 才快进镜像分支 —— 红的代码不进镜像,镜像永远等于主仓。
|
||
#
|
||
# - 只处理 main(feature/release 分支不镜像,与 tag 语义一致)。
|
||
# - 未配置 GITCODE_TOKEN 时显式跳过(与 release.yml 的 sync-gitcode 同口径,
|
||
# 不阻断 GitHub 侧 CI)。
|
||
# - 用快进 push(非 force):正常流水线下镜像只可能落后,不可能领先;
|
||
# 若出现非快进说明有人动过镜像,此时响亮失败而不是悄悄覆盖 ——
|
||
# 镜像被旁路写入是「单向性被破坏」的信号,值得一次人工确认。
|
||
sync-gitcode-main:
|
||
name: Sync main to gitcode (mirror)
|
||
runs-on: ubuntu-latest
|
||
needs: [go, race, cross, gui, csrc, docs]
|
||
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||
timeout-minutes: 10
|
||
env:
|
||
# ══════════════════════════════════════════════════════════════════
|
||
# ★★ gitcode 镜像目标仓名 —— **本 job 的唯一定义处**。
|
||
# 改 gitcode 仓名时只改这一行;下面推 main 的消费点走 ${GC_REPO}。
|
||
# 与 release.yml 的 sync-gitcode 保持同值(两处各自独立定义,
|
||
# 因为它们是不同的 workflow —— 改的时候两个文件都要改,但每个
|
||
# 文件内部只有一个定义处)。
|
||
#
|
||
# 取值依据(实测 2026-10-21 20:1x,直连不带代理,非推测):
|
||
# $ curl -s -o /dev/null -w '%{http_code}' \
|
||
# https://gitcode.com/JianFeeeee/<repo>
|
||
#
|
||
# https://gitcode.com/JianFeeeee/HologramAgent → 200 ← 当前用这个
|
||
# https://gitcode.com/JianFeeeee/HomeAgent → 301 ← 旧名,跳转到上面
|
||
# https://gitcode.com/JianFeeeee/homeagent-sdk → 200(SDK 仓,另一对象)
|
||
# https://gitcode.com/JianFeeeee/hologramagentsdk → 200(SDK 仓,另一对象)
|
||
# https://gitcode.com/JianFeeeee/homeagentsdk → 404
|
||
# https://gitcode.com/JianFeeeee/HologramAgent-sdk → 404
|
||
#
|
||
# 背景:gitcode 侧镜像仓已由 HomeAgent 改名为 HologramAgent(与 GitHub
|
||
# 主仓同名)。旧地址 HomeAgent 仍 301 跳转,跟随后也能到达,但走重定向
|
||
# ⇒ 别再用它(git 侧会多一跳,且改名前的旧名随时可能被彻底释放)。
|
||
# 判定两仓同一对象:两地址 git ls-remote 的 refs 列表 md5 相同。
|
||
#
|
||
# ⚠ 失败面(与 release.yml 不同,别搞混):
|
||
# 本 job 的 needs 是 [go, race, cross, gui, csrc, docs]。前置检查
|
||
# exit 1 ⇒ 本 job 红 ⇒ **main 的整条 CI 红**(不是只红一格)。
|
||
# 而 release.yml 的 sync-gitcode 只红在镜像同步这一格,GitHub 侧
|
||
# release 产物已经发出去了。
|
||
#
|
||
# 以后再改名:gitcode 侧仓名一变,只改这一行(+ release.yml 与
|
||
# upload_assets.py 各一行,共三个定义点)。
|
||
# ══════════════════════════════════════════════════════════════════
|
||
GC_REPO: JianFeeeee/HologramAgent
|
||
steps:
|
||
- id: tok
|
||
name: 检查 gitcode 凭据
|
||
run: |
|
||
if [ -n "${{ secrets.GITCODE_TOKEN }}" ]; then
|
||
echo "ok=true" >> "$GITHUB_OUTPUT"
|
||
else
|
||
echo "ok=false" >> "$GITHUB_OUTPUT"
|
||
echo " 未配置 GITCODE_TOKEN —— 跳过 gitcode main 同步"
|
||
fi
|
||
- uses: actions/checkout@v7
|
||
if: steps.tok.outputs.ok == 'true'
|
||
with:
|
||
# 必须取完整历史:镜像可能在任意旧提交上,快进需要共同祖先。
|
||
fetch-depth: 0
|
||
# ★ 改名(HomeAgent → HologramAgent)后的必然过渡态:gitcode 上的镜像仓
|
||
# 是**另一个账号下的独立仓库**,改 GitHub 仓名不会自动建出它。
|
||
# 若不在这里显式探测,缺少目标仓时只会得到 git 的原始报错
|
||
# ("repository not found" 混在 push 输出里),看不出是「仓没建」。
|
||
# 语义:token 未配置 = 可选项跳过(上面那步);token 有但仓不存在 = 硬失败。
|
||
- name: 前置检查 gitcode 目标仓是否存在
|
||
if: steps.tok.outputs.ok == 'true'
|
||
env:
|
||
GC_TOKEN: ${{ secrets.GITCODE_TOKEN }}
|
||
run: |
|
||
set -euo pipefail
|
||
GC_URL="https://JianFeeeee:${GC_TOKEN}@gitcode.com"
|
||
# GC_REPO 来自 job 级 env(唯一定义处),此处不重复字面量。
|
||
# 用 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
|
||
- name: 推 main 到 gitcode(快进)
|
||
if: steps.tok.outputs.ok == 'true'
|
||
env:
|
||
GC_TOKEN: ${{ secrets.GITCODE_TOKEN }}
|
||
run: |
|
||
set -euo pipefail
|
||
GC_URL="https://JianFeeeee:${GC_TOKEN}@gitcode.com"
|
||
# GC_REPO 来自 job 级 env(唯一定义处),此处不重复字面量。
|
||
git push "${GC_URL}/${GC_REPO}.git" \
|
||
"refs/heads/main:refs/heads/main"
|
||
echo " gitcode/main 已快进到 ${GITHUB_SHA}"
|