feat(issue): add +comments, +comment-edit, +comment-delete #384
|
|
@ -356,6 +356,11 @@ gitlink-cli issue +batch-delete --owner Gitlink --repo forgeplus --ids 101,102 -
|
|||
# Add a comment
|
||||
gitlink-cli issue +comment --owner Gitlink --repo forgeplus -i 123 -b "Fixed"
|
||||
|
||||
# List, edit, and delete comments
|
||||
gitlink-cli issue +comments --owner Gitlink --repo forgeplus -n 123 --category comment
|
||||
gitlink-cli issue +comment-edit --owner Gitlink --repo forgeplus -n 123 -c 484049 -b "Updated"
|
||||
gitlink-cli issue +comment-delete --owner Gitlink --repo forgeplus -n 123 -c 484049
|
||||
|
||||
# List issue assigners
|
||||
gitlink-cli issue +assigners --owner Gitlink --repo forgeplus
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@
|
|||
"cmd.issue.batch_list.short": "List issue batch maintenance candidates without changing remote data",
|
||||
"cmd.issue.close.short": "Close an issue",
|
||||
"cmd.issue.comment.short": "Add a comment to an issue",
|
||||
"cmd.issue.comment_delete.short": "Delete an issue comment",
|
||||
"cmd.issue.comment_edit.short": "Edit an issue comment",
|
||||
"cmd.issue.comments.short": "List comments (journals) of an issue",
|
||||
"cmd.issue.create.short": "Create a new issue",
|
||||
"cmd.issue.list.short": "List issues",
|
||||
"cmd.issue.short": "Issue operations",
|
||||
|
|
@ -158,6 +161,9 @@
|
|||
"flag.issue.batch_list.limit": "Maximum issues to return, capped at 100",
|
||||
"flag.issue.batch_process.limit": "Maximum issues to process, capped at 100",
|
||||
"flag.issue.body": "Issue description",
|
||||
"flag.issue.comment_id": "Comment (journal) ID",
|
||||
"flag.issue.comments_category": "Journal category filter: comment or operate",
|
||||
"flag.issue.comments_keyword": "Filter comments by keyword",
|
||||
"flag.issue.label": "Label ID",
|
||||
"flag.issue.label_filter": "Filter by existing label",
|
||||
"flag.issue.milestone": "Milestone ID",
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@
|
|||
"cmd.issue.batch_list.short": "列出议题批量维护候选项,不修改远端数据",
|
||||
"cmd.issue.close.short": "关闭议题",
|
||||
"cmd.issue.comment.short": "给议题添加评论",
|
||||
"cmd.issue.comment_delete.short": "删除疑修评论",
|
||||
"cmd.issue.comment_edit.short": "编辑疑修评论",
|
||||
"cmd.issue.comments.short": "列出疑修的评论(journals)",
|
||||
"cmd.issue.create.short": "创建新议题",
|
||||
"cmd.issue.list.short": "列出议题",
|
||||
"cmd.issue.short": "议题操作",
|
||||
|
|
@ -158,6 +161,9 @@
|
|||
"flag.issue.batch_list.limit": "最多返回的议题数,上限 100",
|
||||
"flag.issue.batch_process.limit": "最多处理的议题数,上限 100",
|
||||
"flag.issue.body": "议题描述",
|
||||
"flag.issue.comment_id": "评论(journal)ID",
|
||||
"flag.issue.comments_category": "journal 类别过滤:comment 或 operate",
|
||||
"flag.issue.comments_keyword": "按关键字过滤评论",
|
||||
"flag.issue.label": "标签 ID",
|
||||
"flag.issue.label_filter": "按已有标签筛选",
|
||||
"flag.issue.milestone": "里程碑 ID",
|
||||
|
|
|
|||
|
|
@ -297,6 +297,94 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "comments",
|
||||
Description: tr.T("cmd.issue.comments.short"),
|
||||
Flags: appendIssueNumberFlags(
|
||||
common.Flag{Name: "keyword", Short: "k", Usage: tr.T("flag.issue.comments_keyword")},
|
||||
common.Flag{Name: "category", Usage: tr.T("flag.issue.comments_category")},
|
||||
common.Flag{Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"},
|
||||
common.Flag{Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"},
|
||||
),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
number, err := issueNumberArg(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q := url.Values{}
|
||||
q.Set("page", ctx.Arg("page"))
|
||||
q.Set("limit", ctx.Arg("limit"))
|
||||
if keyword := ctx.Arg("keyword"); keyword != "" {
|
||||
q.Set("keyword", keyword)
|
||||
}
|
||||
if category := ctx.Arg("category"); category != "" {
|
||||
q.Set("category", category)
|
||||
}
|
||||
env, err := ctx.CallAPIWithQuery("GET", fmt.Sprintf("%s/issues/%s/journals", v1RepoPath(ctx), number), q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "comment-edit",
|
||||
Description: tr.T("cmd.issue.comment_edit.short"),
|
||||
Flags: appendIssueNumberFlags(
|
||||
common.Flag{Name: "comment-id", Short: "c", Usage: tr.T("flag.issue.comment_id"), Required: true},
|
||||
common.Flag{Name: "body", Short: "b", Usage: tr.T("flag.comment.body"), Required: true},
|
||||
),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
number, err := issueNumberArg(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commentID, err := parseIssueID(ctx.Arg("comment-id"), "comment-id")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := ctx.RequireArg("body")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env, err := ctx.CallAPI("PATCH", fmt.Sprintf("%s/issues/%s/journals/%d", v1RepoPath(ctx), number, commentID), map[string]interface{}{"notes": body})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "comment-delete",
|
||||
Description: tr.T("cmd.issue.comment_delete.short"),
|
||||
Flags: appendIssueNumberFlags(
|
||||
common.Flag{Name: "comment-id", Short: "c", Usage: tr.T("flag.issue.comment_id"), Required: true},
|
||||
),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
number, err := issueNumberArg(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commentID, err := parseIssueID(ctx.Arg("comment-id"), "comment-id")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env, err := ctx.CallAPI("DELETE", fmt.Sprintf("%s/issues/%s/journals/%d", v1RepoPath(ctx), number, commentID), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "assigners",
|
||||
Description: "List issue assigners",
|
||||
|
|
|
|||
|
|
@ -1127,3 +1127,64 @@ func TestNormalizeIssueStatus(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueCommentsListsJournalsWithFilters(t *testing.T) {
|
||||
var query string
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" || r.URL.Path != "/v1/owner/repo/issues/7/journals.json" {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
query = r.URL.RawQuery
|
||||
writeJSON(t, w, map[string]interface{}{"journals": []interface{}{}})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
args := map[string]string{"number": "7", "keyword": "lgtm", "category": "comment", "page": "1", "limit": "20"}
|
||||
if err := runShortcut(t, server, "comments", args); err != nil {
|
||||
t.Fatalf("comments failed: %v", err)
|
||||
}
|
||||
for _, want := range []string{"keyword=lgtm", "category=comment"} {
|
||||
if !strings.Contains(query, want) {
|
||||
t.Fatalf("expected %q in query, got %q", want, query)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueCommentEditPatchesJournal(t *testing.T) {
|
||||
var payload map[string]interface{}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PATCH" || r.URL.Path != "/v1/owner/repo/issues/7/journals/484049.json" {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
payload = decodeJSON(t, r)
|
||||
writeJSON(t, w, map[string]interface{}{"id": float64(484049)})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
args := map[string]string{"number": "7", "comment-id": "484049", "body": "edited"}
|
||||
if err := runShortcut(t, server, "comment-edit", args); err != nil {
|
||||
t.Fatalf("comment-edit failed: %v", err)
|
||||
}
|
||||
if payload["notes"] != "edited" {
|
||||
t.Fatalf("expected notes=edited, got %v", payload["notes"])
|
||||
}
|
||||
|
||||
args["comment-id"] = "abc"
|
||||
if err := runShortcut(t, server, "comment-edit", args); err == nil {
|
||||
t.Fatal("expected error for non-integer --comment-id")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueCommentDeleteUsesJournalEndpoint(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" || r.URL.Path != "/v1/owner/repo/issues/7/journals/484049.json" {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
writeJSON(t, w, map[string]interface{}{"status": float64(0)})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
if err := runShortcut(t, server, "comment-delete", map[string]string{"number": "7", "comment-id": "484049"}); err != nil {
|
||||
t.Fatalf("comment-delete failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue