Closed
bug: --paginate --json 在零结果时输出 null 而非 [](pr list / actions run list) #456
aflyingtoAdd on  Jul 10Closed at  Jul 27
aflyingtoCollaborators
Jul 10 Create

现象

--paginate --json 在结果为空时输出 null,而非 [];非 paginate 路径正确输出 []。两个命令均命中(pr list + actions run list)。

复现

actions run list(Ascend/pytorch 无流水线运行记录)

$ gc actions run list -R Ascend/pytorch --paginate --json
null                                 # ✗ 应为 []
$ gc actions run list -R Ascend/pytorch --json
[]                                   # ✓ 非 paginate 正确

pr list(强制零结果:不存在分支)

$ gc pr list -R Ascend/pytorch --head zzz-nonexistent --paginate --json
null                                 # ✗ 应为 []
$ gc pr list -R Ascend/pytorch --head zzz-nonexistent --json
[]                                   # ✓ 非 paginate 正确

根因

paginate 路径用 var all []T + append 累积各页结果;当所有页都返回空时,all 保持 nil。cmdutil.WriteJSON(encoding/json)将 nil 切片 marshal 为 null(而非 [])。

非 paginate 路径有 nil 守卫:actions 的 trimRuns(pkg/cmd/actions/run/list/list.go)对 nil 返回 []api.WorkflowRun{} → 输出 [];pr list 非 paginate 路径返回 API 的空切片 → []。

代码位置(同形 pattern):

  • pkg/cmd/pr/list/list.go:202 var all []api.PullRequest + :217 all = append(all, prs...)
  • pkg/cmd/actions/run/list/list.go listRuns paginate 分支 var all []api.WorkflowRun + append

影响

  • agent / 脚本消费 --paginate --json 时期望 JSON 数组;null 破坏数组消费者(需额外 nil 判断),且与 --json(非 paginate,输出 [])不一致。
  • 违反 agent-friendly CLI 契约(spec/foundations/agent-friendly-cli.md:只读命令 --json 输出应稳定可消费)。

修复范围

在 paginate 路径 WriteJSON 前归一化 nil→空切片(两个命令),或统一在 cmdutil.WriteJSON 层处理 nil 切片。建议先在 pr/list 治理以保持与既有命令对齐(PR #377 round-2 评审建议),再同步 actions/run/list。

涉及命令:

  • gc pr list --paginate --json
  • gc actions run list --paginate --json
  • 可能还有其它走 var all []T + paginate 的 list 命令(建议一并排查 pkg/cmd/ 下所有 paginate 实现)。

环境与关联

  • gc 0.7.0+(main 含 #445 后),commit f5533c1
  • 复现仓库:Ascend/pytorch(公共镜像仓,无 GitCode Actions 运行记录)+ infra-test/gctest1
  • 关联:PR #377 round-2 评审非阻塞观察(pkg/cmd/actions/run/list/list.go + pkg/cmd/pr/list/list.go parity)

期望

--paginate --json 零结果时输出 [],与非 paginate 一致。

likedislike
AaflyingtoCollaborators
Jul 10 Added label: risk/lowscope/actionsscope/pr, status/triage,type/bug
liujinshengCollaborators
Jul 10 Comments:

验证记录

  • 当前版本或分支: main @ 340f90c(本地构建 ./gc version)
  • 验证方式: 代码审查 + nil 切片 marshal 行为验证(infra-test/* 仓库 PR 列表对当前 token 返回 403,无法联机复现;该 bug 为确定性的输出格式问题,代码级验证足以确认)
  • 根因确认:
    • pkg/cmd/pr/list/list.go:202 var all []api.PullRequest,paginate 循环于 :217 执行 all = append(all, prs...);当所有页均返回空时 all 保持 nil
    • pkg/cmd/actions/run/list/list.go:194 var all []api.WorkflowRun 为同形 pattern(:210 append)
    • cmdutil.WriteJSON(pkg/cmdutil/output.go:17)经 encoding/json 编码:nil 切片 marshal 为 null,空切片 marshal 为 [](已用最小 Go 程序验证:var nilSlice []int -> null,[]int{} -> [])
    • 非 paginate 路径存在 nil 守卫(如 actions 的 trimRuns 返回 []api.WorkflowRun{}),故输出 [];paginate 路径无此守卫
  • 实际结果: 复现成功。--paginate --json + 零结果 -> null;--json(非 paginate)-> [],两者不一致
  • 结论: bug 成立,继续修复。修复方向:在 paginate 路径 WriteJSON 前归一化 nil -> 空切片(pr list + actions run list),或统一在 cmdutil.WriteJSON 层处理 nil 切片;建议一并排查 pkg/cmd/ 下其它 var all []T + paginate 实现

认领开发,进入 status/in-progress。

likedislike
LliujinshengCollaborators
Jul 10 Added label: status/verified
LliujinshengCollaborators
Jul 10 Added label: status/in-progress
LliujinshengCollaborators
Jul 10 Removed label: status/triage
liujinshengCollaborators
Jul 10 Comments:

开发进度

  • 根因: paginate 路径用 var all []T 累积各页结果,所有页为空时 all 保持 nil;encoding/json 将 nil 切片 marshal 为 null,而非 paginate 路径有 nil 守卫输出 [],两者不一致
  • 主要修改: 采用方案 B(集中式),在共享出口 cmdutil.WriteJSON 新增 normalizeNilSlice,将 nil 切片归一化为空切片;nil interface 保持 null 不变,单对象输出不受影响。改动 pkg/cmdutil/output.go(+21)、新增 pkg/cmdutil/output_test.go、pkg/cmd/pr/list/list_test.go(+36 回归测试)
  • 测试: go test ./... 90 包全部通过;新增测试在修复前失败(输出 null)、修复后通过,TDD 验证可捕获该 bug
  • 实际命令验证: TestListRunPaginateEmptyResultsEmitsEmptyArray 端到端验证 listRun paginate 空结果输出 [];infra-test 仓库对当前 token 返回 403,按规范禁止用个人仓库联机测试,故以单元/集成测试覆盖
  • 安全影响: 纯逻辑改动(reflect 类型判断),无凭证/网络/IO 变化,无密钥风险
  • 风险或未覆盖项: risk/low;改动在共享 WriteJSON 但仅影响 nil 切片(-> []),nil interface 与非切片类型不变;未逐一排查其它传 nil 切片给 WriteJSON 的命令(nil->[] 对 JSON 数组语义始终正确,不构成风险)
  • 关联 PR: #390
likedislike
LliujinshengCollaborators
Jul 10 Added label: status/ready-for-review
LliujinshengCollaborators
Jul 10 Removed label: status/in-progress
LliujinshengCollaborators
Jul 22 Added label: status/in-progress
LliujinshengCollaborators
Jul 22 Removed label: status/ready-for-review
AaflyingtoCollaborators
Jul 25 Associated milestone: M2: Agent-Friendly Compliance Phase 3
AaflyingtoCollaborators
Jul 27 Close issue