forked from Gitlink/gitlink-cli
Merge pull request 'feat(repo): 新增 repo +tree 文件树查询命令' (#143) from ohanabi/gitlink-cli:feat/repo-tree-shortcut-final into master
This commit is contained in:
commit
462ae7b012
|
|
@ -204,6 +204,10 @@ gitlink-cli repo +info --owner Gitlink --repo forgeplus
|
|||
# Read repository README
|
||||
gitlink-cli repo +readme --owner Gitlink --repo forgeplus --ref master
|
||||
|
||||
# List repository files at root or a directory
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --ref master
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --path src --ref main
|
||||
|
||||
# Show language breakdown
|
||||
gitlink-cli repo +languages --owner Gitlink --repo forgeplus
|
||||
|
||||
|
|
|
|||
|
|
@ -215,6 +215,10 @@ gitlink-cli repo +info --owner Gitlink --repo forgeplus
|
|||
# 读取仓库 README
|
||||
gitlink-cli repo +readme --owner Gitlink --repo forgeplus --ref master
|
||||
|
||||
# 列出仓库根目录或指定目录文件
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --ref master
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --path src --ref main
|
||||
|
||||
# 查看语言占比
|
||||
gitlink-cli repo +languages --owner Gitlink --repo forgeplus
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
# repo +tree 仓库文件树查询命令
|
||||
|
||||
## 背景
|
||||
|
||||
`gitlink-cli repo` 已经提供仓库详情、README、语言统计和贡献者查询能力,但缺少直接查看仓库目录结构的 Shortcut。用户或 AI Agent 如果要判断仓库中是否存在 README、LICENSE、依赖清单、测试目录、文档目录等文件,过去需要手动调用 Raw API `/sub_entries`。
|
||||
|
||||
本次变更把仓库文件树查询封装为 `repo +tree`,降低普通用户和自动化工作流的使用门槛。
|
||||
|
||||
## 变更内容
|
||||
|
||||
- 新增 `gitlink-cli repo +tree` Shortcut。
|
||||
- 调用 `GET /{owner}/{repo}/sub_entries` 获取仓库根目录或指定目录下的文件和子目录。
|
||||
- 支持 `--path, -p` 指定目录路径;不传时查询仓库根目录。
|
||||
- 支持 `--ref, -r` 指定分支、标签或提交引用;默认值为 `master`。
|
||||
- 复用现有仓库上下文解析、API 调用和统一输出格式。
|
||||
- 补充中英文 i18n 文案,避免新增命令帮助信息硬编码。
|
||||
|
||||
## 命令示例
|
||||
|
||||
```bash
|
||||
# 查看仓库根目录
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --ref master
|
||||
|
||||
# 查看指定目录
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --path src --ref main
|
||||
|
||||
# Agent 场景建议使用 JSON 输出
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --format json
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `--path, -p` | 否 | 要查看的目录路径,不传时查询仓库根目录 |
|
||||
| `--ref, -r` | 否 | 分支、标签或提交引用,默认 `master` |
|
||||
| `--owner` | 否 | 全局参数,仓库所有者,可从 git remote 自动解析 |
|
||||
| `--repo` | 否 | 全局参数,仓库名称,可从 git remote 自动解析 |
|
||||
| `--format` | 否 | 全局参数,输出格式:`json`、`table` 或 `yaml` |
|
||||
|
||||
## 测试覆盖
|
||||
|
||||
单元测试覆盖以下内容:
|
||||
|
||||
- 根目录查询默认使用 `master`。
|
||||
- 根目录查询不发送空 `filepath` 参数。
|
||||
- 指定 `--path` 和 `--ref` 时正确映射到 `filepath` 与 `ref` 查询参数。
|
||||
- `repo +tree` 的命令说明和 `--path/-p`、`--ref/-r` 参数注册完整。
|
||||
|
||||
验证命令:
|
||||
|
||||
```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`
|
||||
|
||||
## 兼容性
|
||||
|
||||
该变更只新增 Shortcut、单元测试和文档,不修改已有命令参数或输出结构。根目录查询时不再发送空 `filepath` 查询参数,语义更清晰,对现有功能无破坏性影响。
|
||||
|
|
@ -40,7 +40,7 @@ gitlink-cli/
|
|||
│ ├── common/
|
||||
│ │ ├── types.go # Shortcut / Flag / RuntimeContext 定义
|
||||
│ │ └── runner.go # CallAPI / PaginateAll / ResolveOwnerRepo
|
||||
│ ├── repo/ # repo +create / +clone / +fork / +list / +info
|
||||
│ ├── repo/ # repo +list / +info / +readme / +tree / +languages / +create ...
|
||||
│ ├── issue/ # issue +list / +create / +view / +close / +comment
|
||||
│ ├── pr/ # pr +list / +create / +view / +merge / +review
|
||||
│ ├── release/ # release +list / +create / +download
|
||||
|
|
@ -78,7 +78,7 @@ gitlink-cli/
|
|||
|
||||
| 领域 | Shortcuts | 数量 |
|
||||
|------|-----------|------|
|
||||
| repo | `+create` `+clone` `+fork` `+list` `+info` `+delete` `+settings` | 7 |
|
||||
| repo | `+list` `+info` `+readme` `+tree` `+languages` `+contributors` `+contributor-stats` `+code-stats` `+watchers` `+stargazers` `+follow` `+unfollow` `+like` `+unlike` `+create` `+fork` `+delete` | 17 |
|
||||
| issue | `+list` `+create` `+view` `+update` `+close` `+comment` `+assign` `+label` | 8 |
|
||||
| pr | `+list` `+create` `+view` `+merge` `+close` `+review` `+files` `+diff` | 8 |
|
||||
| release | `+list` `+create` `+view` `+delete` `+download` | 5 |
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
"cmd.repo.info.short": "Show repository details",
|
||||
"cmd.repo.list.short": "List repositories for a user or organization",
|
||||
"cmd.repo.short": "Repository operations",
|
||||
"cmd.repo.tree.short": "List repository files and directories",
|
||||
"cmd.root.long": "Manage repositories, issues, pull requests, releases, CI and workflows on GitLink.",
|
||||
"cmd.root.short": "GitLink CLI - command-line tool for GitLink",
|
||||
"cmd.search.repos.short": "Search repositories",
|
||||
|
|
@ -172,6 +173,8 @@
|
|||
"flag.repo.description": "Repository description",
|
||||
"flag.repo.name": "Repository name",
|
||||
"flag.repo.private": "Make repository private (true/false)",
|
||||
"flag.repo.tree.path": "Directory path to list (default: repository root)",
|
||||
"flag.repo.tree.ref": "Branch, tag, or commit ref",
|
||||
"flag.search.keyword": "Search keyword",
|
||||
"flag.sort_by": "Sort field",
|
||||
"flag.sort_direction": "Sort direction: asc, desc",
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
"cmd.repo.info.short": "显示仓库详情",
|
||||
"cmd.repo.list.short": "列出用户或组织的仓库",
|
||||
"cmd.repo.short": "仓库操作",
|
||||
"cmd.repo.tree.short": "列出仓库文件和目录",
|
||||
"cmd.root.long": "用于管理 GitLink 上的仓库、议题、拉取请求、发布、CI 和工作流。",
|
||||
"cmd.root.short": "GitLink CLI - GitLink 命令行工具",
|
||||
"cmd.search.repos.short": "搜索仓库",
|
||||
|
|
@ -172,6 +173,8 @@
|
|||
"flag.repo.description": "仓库描述",
|
||||
"flag.repo.name": "仓库名称",
|
||||
"flag.repo.private": "设为私有仓库(true/false)",
|
||||
"flag.repo.tree.path": "要列出的目录路径(默认:仓库根目录)",
|
||||
"flag.repo.tree.ref": "分支、标签或提交引用",
|
||||
"flag.search.keyword": "搜索关键词",
|
||||
"flag.sort_by": "排序字段",
|
||||
"flag.sort_direction": "排序方向:asc、desc",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,33 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "tree",
|
||||
Description: tr.T("cmd.repo.tree.short"),
|
||||
Flags: []common.Flag{
|
||||
{Name: "path", Short: "p", Usage: tr.T("flag.repo.tree.path")},
|
||||
{Name: "ref", Short: "r", Usage: tr.T("flag.repo.tree.ref"), Default: "master"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
q := url.Values{}
|
||||
ref := ctx.Arg("ref")
|
||||
if ref == "" {
|
||||
ref = "master"
|
||||
}
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "languages",
|
||||
Description: "Show repository language statistics",
|
||||
|
|
|
|||
|
|
@ -152,6 +152,72 @@ 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")
|
||||
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{}{
|
||||
{"name": "README.md", "type": "file"},
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
if err := runShortcut(t, server, "tree", nil); err != nil {
|
||||
t.Fatalf("tree shortcut failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoTreeUsesPathAndRef(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"), "cmd")
|
||||
assertEqual(t, r.URL.Query().Get("ref"), "main")
|
||||
writeJSON(t, w, map[string]interface{}{
|
||||
"entries": []map[string]interface{}{
|
||||
{"name": "main.go", "type": "file"},
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
if err := runShortcut(t, server, "tree", map[string]string{"path": "cmd", "ref": "main"}); err != nil {
|
||||
t.Fatalf("tree shortcut failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ metadata:
|
|||
| `repo +list` | 仓库列表 | 否(公开项目) |
|
||||
| `repo +info` | 仓库详情 | 否(公开项目) |
|
||||
| `repo +readme` | README 内容 | 否(公开项目) |
|
||||
| `repo +tree` | 仓库文件树 | 否(公开项目) |
|
||||
| `repo +languages` | 仓库语言统计 | 否(公开项目) |
|
||||
| `repo +contributors` | 仓库贡献者列表 | 否(公开项目) |
|
||||
| `repo +contributor-stats` | 贡献者代码行统计 | 否(公开项目) |
|
||||
|
|
@ -50,7 +51,9 @@ gitlink-cli repo +info
|
|||
# 列出用户的仓库
|
||||
gitlink-cli repo +list --user zhangsan
|
||||
|
||||
# 查看语言占比和贡献者
|
||||
# 查看文件树、语言占比和贡献者
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --ref master
|
||||
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --path src --ref main
|
||||
gitlink-cli repo +languages --owner Gitlink --repo forgeplus
|
||||
gitlink-cli repo +contributors --owner Gitlink --repo forgeplus
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
# repo +tree
|
||||
|
||||
> **前置条件:** 先阅读 [`../gitlink-shared/SKILL.md`](../../gitlink-shared/SKILL.md) 了解认证、全局参数和安全规则。
|
||||
|
||||
列出 GitLink 仓库根目录或指定目录下的文件和子目录。该命令封装 `sub_entries` API,适合项目结构检查、文档检查、科研复现性分析和 Agent 自动化报告。
|
||||
|
||||
## 命令
|
||||
|
||||
```bash
|
||||
# 列出仓库根目录
|
||||
gitlink-cli repo +tree --owner someone --repo myrepo
|
||||
|
||||
# 指定分支、标签或提交
|
||||
gitlink-cli repo +tree --owner someone --repo myrepo --ref main
|
||||
|
||||
# 列出指定目录
|
||||
gitlink-cli repo +tree --owner someone --repo myrepo --path src --ref main
|
||||
|
||||
# 输出为 JSON
|
||||
gitlink-cli repo +tree --owner someone --repo myrepo --format json
|
||||
```
|
||||
|
||||
## 参数
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `--path, -p` | 否 | 要列出的目录路径,默认为仓库根目录 |
|
||||
| `--ref, -r` | 否 | 分支、标签或提交引用,默认 `master` |
|
||||
| `--owner` | 否 | 全局参数 - 仓库所有者,可从 git remote 自动解析 |
|
||||
| `--repo` | 否 | 全局参数 - 仓库名称,可从 git remote 自动解析 |
|
||||
| `--format` | 否 | 输出格式:`json`/`table`/`yaml` |
|
||||
| `--debug` | 否 | 启用调试输出 |
|
||||
|
||||
## 注意事项
|
||||
|
||||
- GitLink 仓库常见默认分支是 `master`,镜像仓库也可能使用 `main`。如果根目录返回不存在,请显式指定 `--ref main` 或从 `repo +info` 的 `default_branch` 字段确认。
|
||||
- AI Agent 场景建议使用 `--format json`,便于读取 `data.entries` 中的文件名、路径、类型和 SHA。
|
||||
|
||||
## 参考
|
||||
|
||||
- [gitlink-repo](../SKILL.md)
|
||||
- [gitlink-shared](../../gitlink-shared/SKILL.md)
|
||||
Loading…
Reference in New Issue