diff --git a/shortcuts/issue/batch_create.go b/shortcuts/issue/batch_create.go index 0c59c1d2..15534299 100644 --- a/shortcuts/issue/batch_create.go +++ b/shortcuts/issue/batch_create.go @@ -12,20 +12,21 @@ import ( "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) -var issueTagCache sync.Map +var issueTagCache sync.Map //全局缓存变量 +// 获取项目标签映射 // resolveIssueTags fetches the project's issue tags and returns a name→id mapping. // Results are cached per owner/repo. func resolveIssueTags(ctx *common.RuntimeContext) (map[string]int, error) { key := ctx.Owner + "/" + ctx.Repo - if cached, ok := issueTagCache.Load(key); ok { - return cached.(map[string]int), nil + if cached, ok := issueTagCache.Load(key); ok { //先从缓存查 + return cached.(map[string]int), nil // 命中缓存则直接返回 } - path := fmt.Sprintf("/v1/%s/%s/issue_tags", ctx.Owner, ctx.Repo) + path := fmt.Sprintf("/v1/%s/%s/issue_tags", ctx.Owner, ctx.Repo) //api路径 q := url.Values{} q.Set("only_name", "true") - env, err := ctx.CallAPIWithQuery("GET", path, q) + env, err := ctx.CallAPIWithQuery("GET", path, q) // 发送GET请求获取项目标签列表 if err != nil { return nil, fmt.Errorf("获取项目标签列表失败: %w", err) } @@ -157,7 +158,7 @@ func runBatchCreate(ctx *common.RuntimeContext) error { for i, input := range inputs { label := fmt.Sprintf("#%d", i+1) if input.Title != "" { - label = truncate(input.Title, 40) + label = truncate(input.Title, 40) // 用标题的前40个字符 } result := BatchResult{Number: label, Action: "create"} @@ -168,6 +169,7 @@ func runBatchCreate(ctx *common.RuntimeContext) error { continue } + //把 createIssueInput 转换成 API 需要的 JSON map body := buildCreateBody(ctx, input, template, tags) env, err := ctx.CallAPI("POST", v1RepoPath(ctx)+"/issues", body) if err != nil { diff --git a/shortcuts/issue/issue.go b/shortcuts/issue/issue.go index e0efc6b7..b6501da2 100644 --- a/shortcuts/issue/issue.go +++ b/shortcuts/issue/issue.go @@ -1,24 +1,28 @@ package issue import ( - "fmt" + "fmt" //格式化字符串 "net/url" - "strconv" + "strconv" //字符串和数字转换 "strings" - "github.com/gitlink-org/gitlink-cli/shortcuts/common" + "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) +// Ctx // v1RepoPath returns the v1 API path prefix: /v1/{owner}/{repo} func v1RepoPath(ctx *common.RuntimeContext) string { return fmt.Sprintf("/v1/%s/%s", ctx.Owner, ctx.Repo) } +//内部数据结构,标题+描述,保存从 API 取回来的 Issue 原始数据 type existingIssue struct { Subject string Description string } +// 所有issue命令的注册入口,返回所有issue命令 +// 在终端敲入issue +list命令时,遍历匹配到列表里的{Name: "list", ...} func Shortcuts() []*common.Shortcut { return []*common.Shortcut{ newBatchCloseShortcut(), @@ -38,21 +42,23 @@ func Shortcuts() []*common.Shortcut { {Name: "page", Short: "p", Usage: "Page number", Default: "1"}, {Name: "limit", Short: "l", Usage: "Items per page", Default: "20"}, }, - Run: func(ctx *common.RuntimeContext) error { + //后面拼接 API 路径时,需要用到 ctx.Owner 和 ctx.Repo + // 如果不知道 owner 和 repo ,后续的 API 调用就不知道该往哪发请求,所以必须作为前置校验放在最前面。 + 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 s := ctx.Arg("state"); s != "" { + q := url.Values{} // 创建空的URL查询参数容器q,后续通过set()添加键值对,最终拼接成形如 ?page=1&limit=20&state=open 的查询字符串 + q.Set("page", ctx.Arg("page")) + q.Set("limit", ctx.Arg("limit")) //从命令行参数中读取 page(页码)和 limit(每页条数 + if s := ctx.Arg("state"); s != "" { // 如果用户传入了state参数 q.Set("state", s) } env, err := ctx.CallAPIWithQuery("GET", v1RepoPath(ctx)+"/issues", q) if err != nil { return fmt.Errorf("获取 Issue 列表失败: %w", err) } - return ctx.Output(env) + return ctx.Output(env) //按照用户指定的格式(json/html/table...)输出issue列表 }, }, {