diff --git a/doc/changes/list-all-pagination.md b/doc/changes/list-all-pagination.md index cf4cbb8..6048934 100644 --- a/doc/changes/list-all-pagination.md +++ b/doc/changes/list-all-pagination.md @@ -16,14 +16,15 @@ - 遵循 `total_count`:达到总数即停止;另设最大页数护栏,防止 忽略 `page` 参数的端点造成死循环。 - `PaginateAll` 保持原签名,委托给 `PaginateAllKey`。 -- 十五个分页 list 命令新增 `--all` 布尔参数(默认 false): +- 十七个分页 list 命令新增 `--all` 布尔参数(默认 false): - `issue +list --all`(合并结果同样应用 number/database_id 规范化) - `pr +list --all`、`branch +list --all`、`release +list --all` - `milestone +list --all`、`org +list --all`、`repo +list --all` - `search +repos --all`、`search +users --all` - `label +list --all`、`member +list --all`、`webhook +list --all` - `issue +comments --all`(新增子命令,见下) - - `tag +list --all`(新增命令组,见下)、`repo +watchers/+stargazers --all` + - `tag +list --all`、`commit +list --all`(新增命令组,见下) + - `repo +watchers/+stargazers/+forks --all` - 对应资源键:`issues`/`pulls`/`branches`/`releases`/`milestones`/ `organizations`/`projects`/`users`/`issue_tags`/`collaborators`/`webhooks` (均生产实测确认) @@ -40,6 +41,11 @@ - 新增 `tag +list` 命令组:平台暴露分页的 `/v1/:owner/:repo/tags` 端点(轻量 tag 与 release 不同),但 CLI 此前完全没有 tag 命令; 生产实测 forgeplus 16 个 tag 分页与 --all 合并均通过。 +- 新增 `commit +list` 命令组:分页的 `/v1/:owner/:repo/commits` + 端点此前只能通过裸 api 命令访问;支持 `--ref` 指定分支/tag/SHA + (映射 sha 参数,生产实测 forgeplus 6762 commits、develop 5346)。 +- 新增 `repo +forks`:分页的 forks 列表(总数键 `count`, + 生产实测 forgeplus 77 个 fork 全量合并);此前只有 fork 创建命令。 - 修复翻页助手服务端封顶 limit 丢数据 bug:当端点把请求的 limit 封顶(如请求 100 每页只返 20)时,旧逻辑因「页内条数 < limit」提前 终止只拿到首页;现已知 total 时以 total 为准(watchers 264 条全量 diff --git a/shortcuts/commit/commit.go b/shortcuts/commit/commit.go new file mode 100644 index 0000000..4573db6 --- /dev/null +++ b/shortcuts/commit/commit.go @@ -0,0 +1,52 @@ +package commit + +import ( + "fmt" + "net/url" + + "github.com/gitlink-org/gitlink-cli/shortcuts/common" +) + +// Shortcuts returns commit history shortcuts. +// +// Commit history previously had no first-class command even though the +// platform exposes a paginated v1 endpoint; agents had to fall back to the +// raw api command to read it. +func Shortcuts() []*common.Shortcut { + return []*common.Shortcut{ + { + Name: "list", + Description: "List repository commits", + Flags: []common.Flag{ + {Name: "ref", Short: "r", Usage: "Branch, tag, or commit SHA to start from (default branch when omitted)"}, + {Name: "page", Short: "p", Usage: "Page number", Default: "1"}, + {Name: "limit", Short: "l", Usage: "Items per page", Default: "20"}, + {Name: "all", Usage: "Fetch all pages automatically (ignores --page)", Bool: true, Default: "false"}, + }, + Run: func(ctx *common.RuntimeContext) error { + if err := ctx.ResolveOwnerRepo(); err != nil { + return err + } + path := fmt.Sprintf("/v1/%s/%s/commits", ctx.Owner, ctx.Repo) + q := url.Values{} + q.Set("page", ctx.Arg("page")) + q.Set("limit", ctx.Arg("limit")) + if ref := ctx.Arg("ref"); ref != "" { + q.Set("sha", ref) + } + if ctx.Arg("all") == "true" { + items, err := ctx.PaginateAllKey(path, q, "commits") + if err != nil { + return err + } + return ctx.Output(common.NewListEnvelope("commits", items)) + } + env, err := ctx.CallAPIWithQuery("GET", path, q) + if err != nil { + return err + } + return ctx.Output(env) + }, + }, + } +} diff --git a/shortcuts/register.go b/shortcuts/register.go index e2045ec..8876c25 100644 --- a/shortcuts/register.go +++ b/shortcuts/register.go @@ -6,6 +6,7 @@ import ( "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/branch" "github.com/gitlink-org/gitlink-cli/shortcuts/ci" + "github.com/gitlink-org/gitlink-cli/shortcuts/commit" "github.com/gitlink-org/gitlink-cli/shortcuts/common" "github.com/gitlink-org/gitlink-cli/shortcuts/compare" "github.com/gitlink-org/gitlink-cli/shortcuts/dataset" @@ -52,6 +53,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { "user": user.Shortcuts(tr), "search": search.Shortcuts(tr), "tag": tag.Shortcuts(), + "commit": commit.Shortcuts(), "ci": ci.Shortcuts(tr), "compare": compare.Shortcuts(), "dataset": dataset.Shortcuts(tr), @@ -78,6 +80,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { "user": tr.T("cmd.user.short"), "search": tr.T("cmd.search.short"), "tag": "Git tag operations", + "commit": "Commit history operations", "ci": tr.T("cmd.ci.short"), "compare": "Compare branches, tags, or commits", "dataset": tr.T("cmd.dataset.short"), diff --git a/shortcuts/register_test.go b/shortcuts/register_test.go index 887e9f3..2957f18 100644 --- a/shortcuts/register_test.go +++ b/shortcuts/register_test.go @@ -12,7 +12,7 @@ func TestRegisterAll(t *testing.T) { expectedGroups := []string{ "repo", "issue", "label", "license", "pr", "profile", "release", "branch", - "org", "user", "search", "tag", "ci", "workflow", + "org", "user", "search", "tag", "commit", "ci", "workflow", "compare", "member", "milestone", "pipeline", "webhook", "dataset", "health", "ignore", "wiki", } diff --git a/shortcuts/repo/repo.go b/shortcuts/repo/repo.go index 922c7c4..3414c36 100644 --- a/shortcuts/repo/repo.go +++ b/shortcuts/repo/repo.go @@ -159,6 +159,35 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { return runCommunityList(ctx, "stargazers") }, }, + { + Name: "forks", + Description: "List repository forks", + Flags: []common.Flag{ + {Name: "page", Short: "p", Usage: "Page number", Default: "1"}, + {Name: "limit", Short: "l", Usage: "Items per page", Default: "20"}, + {Name: "all", Usage: "Fetch all pages automatically (ignores --page)", Bool: true, Default: "false"}, + }, + Run: func(ctx *common.RuntimeContext) error { + if err := ctx.ResolveOwnerRepo(); err != nil { + return err + } + q := url.Values{} + q.Set("page", ctx.Arg("page")) + q.Set("limit", ctx.Arg("limit")) + if ctx.Arg("all") == "true" { + items, err := ctx.PaginateAllKey(ctx.RepoPath()+"/forks", q, "users") + if err != nil { + return err + } + return ctx.Output(common.NewListEnvelope("users", items)) + } + env, err := ctx.CallAPIWithQuery("GET", ctx.RepoPath()+"/forks", q) + if err != nil { + return err + } + return ctx.Output(env) + }, + }, { Name: "follow", Description: "Follow a repository",