chore: 打磨仓库文件树命令交付质量

This commit is contained in:
NeeNe 2026-06-08 12:13:28 +08:00
parent 0da1d8d7bf
commit 21ebb2f89c
3 changed files with 72 additions and 35 deletions

View File

@ -1,60 +1,65 @@
# Repo Tree Shortcut
# repo +tree 仓库文件树查询命令
## Summary
## 背景
Adds `gitlink-cli repo +tree` so users and AI Agents can list repository files and directories without manually calling the Raw API.
`gitlink-cli repo` 已经提供仓库详情、README、语言统计和贡献者查询能力但缺少直接查看仓库目录结构的 Shortcut。用户或 AI Agent 如果要判断仓库中是否存在 README、LICENSE、依赖清单、测试目录、文档目录等文件过去需要手动调用 Raw API `/sub_entries`
## Command
本次变更把仓库文件树查询封装为 `repo +tree`,降低普通用户和自动化工作流的使用门槛。
| Command | Purpose |
|---------|---------|
| `gitlink-cli repo +tree` | List repository files and directories at the repository root or a specified path |
## 变更内容
## Usage
- 新增 `gitlink-cli repo +tree` Shortcut。
- 调用 `GET /{owner}/{repo}/sub_entries` 获取仓库根目录或指定目录下的文件和子目录。
- 支持 `--path, -p` 指定目录路径;不传时查询仓库根目录。
- 支持 `--ref, -r` 指定分支、标签或提交引用;默认值为 `master`
- 复用现有仓库上下文解析、API 调用和统一输出格式。
- 补充中英文 i18n 文案,避免新增命令帮助信息硬编码。
## 命令示例
```bash
# List repository root entries
# 查看仓库根目录
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --ref master
# List entries under a directory
# 查看指定目录
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --path src --ref main
# AI Agent usage with structured output
# Agent 场景建议使用 JSON 输出
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --format json
```
## Behavior
## 参数说明
- Calls `GET /{owner}/{repo}/sub_entries`.
- Maps `--path, -p` to the `filepath` query parameter.
- Maps `--ref, -r` to the `ref` query parameter.
- Defaults `--ref` to `master` when omitted.
- Reuses existing repository context resolution and output formatting.
| 参数 | 必填 | 说明 |
|------|------|------|
| `--path, -p` | 否 | 要查看的目录路径,不传时查询仓库根目录 |
| `--ref, -r` | 否 | 分支、标签或提交引用,默认 `master` |
| `--owner` | 否 | 全局参数,仓库所有者,可从 git remote 自动解析 |
| `--repo` | 否 | 全局参数,仓库名称,可从 git remote 自动解析 |
| `--format` | 否 | 全局参数,输出格式:`json`、`table` 或 `yaml` |
## Tests
## 测试覆盖
Unit tests cover:
单元测试覆盖以下内容:
- root directory listing with the default `master` ref;
- directory listing with explicit `--path` and `--ref`;
- endpoint path and query parameter mapping.
- 根目录查询默认使用 `master`
- 根目录查询不发送空 `filepath` 参数。
- 指定 `--path``--ref` 时正确映射到 `filepath``ref` 查询参数。
- `repo +tree` 的命令说明和 `--path/-p`、`--ref/-r` 参数注册完整。
Validation command:
验证命令:
```bash
make test
```
## 中文说明
## 交付要求核对
### 变更内容
- 功能代码:`shortcuts/repo/repo.go`
- 单元测试:`shortcuts/repo/repo_test.go`
- 命令帮助文档:`README.md`、`README.zh-CN.md`、`skills/gitlink-repo/SKILL.md`、`skills/gitlink-repo/references/gitlink-repo-tree.md`
- 变更说明文档:`doc/changes/repo-tree-shortcut.md`
- 新增 `repo +tree` 仓库文件树查询命令。
- 支持查看仓库根目录或指定目录下的文件和子目录。
- 支持通过 `--ref` 指定分支、标签或提交引用。
- 更新 README、README.zh-CN、设计文档和 `gitlink-repo` Skill 文档。
- 新增 `gitlink-repo` Skill 参考文档,便于 Agent 在项目结构检查、复现性检查和合规检查中复用。
## 兼容性
### 验证
- `make test`
该变更只新增 Shortcut、单元测试和文档不修改已有命令参数或输出结构。根目录查询时不再发送空 `filepath` 查询参数,语义更清晰,对现有功能无破坏性影响。

View File

@ -97,7 +97,9 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
if ref == "" {
ref = "master"
}
q.Set("filepath", ctx.Arg("path"))
if path := ctx.Arg("path"); path != "" {
q.Set("filepath", path)
}
q.Set("ref", ref)
env, err := ctx.CallAPIWithQuery("GET", ctx.RepoPath()+"/sub_entries", q)
if err != nil {

View File

@ -155,7 +155,9 @@ func TestRepoReadmeUsesRepositoryReadmeEndpoint(t *testing.T) {
func TestRepoTreeListsRootOnDefaultRef(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assertRequest(t, r, "GET", "/owner/repo/sub_entries.json")
assertEqual(t, r.URL.Query().Get("filepath"), "")
if _, ok := r.URL.Query()["filepath"]; ok {
t.Fatalf("did not expect filepath query for repository root, got %q", r.URL.Query().Get("filepath"))
}
assertEqual(t, r.URL.Query().Get("ref"), "master")
writeJSON(t, w, map[string]interface{}{
"entries": []map[string]interface{}{
@ -188,6 +190,34 @@ func TestRepoTreeUsesPathAndRef(t *testing.T) {
}
}
func TestRepoTreeShortcutRegistersHelpFlags(t *testing.T) {
tree := findShortcut(t, "tree")
if tree.Description == "" {
t.Fatal("tree shortcut description is empty")
}
flags := map[string]common.Flag{}
for _, flag := range tree.Flags {
flags[flag.Name] = flag
}
pathFlag, ok := flags["path"]
if !ok {
t.Fatal("tree shortcut missing path flag")
}
if pathFlag.Short != "p" || pathFlag.Usage == "" {
t.Fatalf("unexpected path flag: %+v", pathFlag)
}
refFlag, ok := flags["ref"]
if !ok {
t.Fatal("tree shortcut missing ref flag")
}
if refFlag.Short != "r" || refFlag.Default != "master" || refFlag.Usage == "" {
t.Fatalf("unexpected ref flag: %+v", refFlag)
}
}
func TestRepoLanguagesUsesLanguagesEndpoint(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assertRequest(t, r, "GET", "/owner/repo/languages.json")