mirror of
https://gitea.com/gitea/tea.git
synced 2024-11-22 02:21:36 +01:00
Add tea comment
and show comments of issues/pulls (#313)
show comments of PR TODO: there needs to be a way to force running non-interactively add `tea comment` to post a comment add --comments flag, prompt only if necessary don't prompt if --comments is provided, or output is piped show comments for issues, add --comments flag tea comment: print resulting comment Merge branch 'master' into issue-172-comments remove debug print statement unrelated, but better than opening another PR for this ;) Merge remote-tracking branch 'upstream/master' into issue-172-comments ret err fix lint Co-authored-by: Norwin Roosen <git@nroo.de> Co-authored-by: 6543 <6543@obermui.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/313 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-by: 6543 <6543@obermui.de> Co-Authored-By: Norwin <noerw@noreply.gitea.io> Co-Committed-By: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
parent
9efee7bf99
commit
32b7b771cc
65
cmd/comment.go
Normal file
65
cmd/comment.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/tea/modules/interact"
|
||||||
|
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
|
"code.gitea.io/tea/cmd/flags"
|
||||||
|
"code.gitea.io/tea/modules/context"
|
||||||
|
"code.gitea.io/tea/modules/print"
|
||||||
|
"code.gitea.io/tea/modules/utils"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CmdAddComment is the main command to operate with notifications
|
||||||
|
var CmdAddComment = cli.Command{
|
||||||
|
Name: "comment",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Category: catEntities,
|
||||||
|
Usage: "Add a comment to an issue / pr",
|
||||||
|
Description: "Add a comment to an issue / pr",
|
||||||
|
ArgsUsage: "<issue / pr index> [<comment body>]",
|
||||||
|
Action: runAddComment,
|
||||||
|
Flags: flags.AllDefaultFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runAddComment(cmd *cli.Context) error {
|
||||||
|
ctx := context.InitCommand(cmd)
|
||||||
|
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||||
|
|
||||||
|
args := ctx.Args()
|
||||||
|
if args.Len() == 0 {
|
||||||
|
return fmt.Errorf("Please specify issue / pr index")
|
||||||
|
}
|
||||||
|
|
||||||
|
idx, err := utils.ArgToIndex(ctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body := strings.Join(ctx.Args().Tail(), " ")
|
||||||
|
if len(body) == 0 {
|
||||||
|
if body, err = interact.PromptMultiline("Content"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client := ctx.Login.Client()
|
||||||
|
comment, _, err := client.CreateIssueComment(ctx.Owner, ctx.Repo, idx, gitea.CreateIssueCommentOption{
|
||||||
|
Body: body,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
print.Comment(comment)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -5,8 +5,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/tea/cmd/issues"
|
"code.gitea.io/tea/cmd/issues"
|
||||||
"code.gitea.io/tea/modules/context"
|
"code.gitea.io/tea/modules/context"
|
||||||
|
"code.gitea.io/tea/modules/interact"
|
||||||
"code.gitea.io/tea/modules/print"
|
"code.gitea.io/tea/modules/print"
|
||||||
"code.gitea.io/tea/modules/utils"
|
"code.gitea.io/tea/modules/utils"
|
||||||
|
|
||||||
@ -19,7 +22,7 @@ var CmdIssues = cli.Command{
|
|||||||
Aliases: []string{"issue", "i"},
|
Aliases: []string{"issue", "i"},
|
||||||
Category: catEntities,
|
Category: catEntities,
|
||||||
Usage: "List, create and update issues",
|
Usage: "List, create and update issues",
|
||||||
Description: "List, create and update issues",
|
Description: `Lists issues when called without argument. If issue index is provided, will show it in detail.`,
|
||||||
ArgsUsage: "[<issue index>]",
|
ArgsUsage: "[<issue index>]",
|
||||||
Action: runIssues,
|
Action: runIssues,
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
@ -28,7 +31,12 @@ var CmdIssues = cli.Command{
|
|||||||
&issues.CmdIssuesReopen,
|
&issues.CmdIssuesReopen,
|
||||||
&issues.CmdIssuesClose,
|
&issues.CmdIssuesClose,
|
||||||
},
|
},
|
||||||
Flags: issues.CmdIssuesList.Flags,
|
Flags: append([]cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "comments",
|
||||||
|
Usage: "Wether to display comments (will prompt if not provided & run interactively)",
|
||||||
|
},
|
||||||
|
}, issues.CmdIssuesList.Flags...),
|
||||||
}
|
}
|
||||||
|
|
||||||
func runIssues(ctx *cli.Context) error {
|
func runIssues(ctx *cli.Context) error {
|
||||||
@ -51,5 +59,13 @@ func runIssueDetail(cmd *cli.Context, index string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
print.IssueDetails(issue)
|
print.IssueDetails(issue)
|
||||||
|
|
||||||
|
if issue.Comments > 0 {
|
||||||
|
err = interact.ShowCommentsMaybeInteractive(ctx, idx, issue.Comments)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error loading comments: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
19
cmd/pulls.go
19
cmd/pulls.go
@ -7,9 +7,9 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/tea/cmd/flags"
|
|
||||||
"code.gitea.io/tea/cmd/pulls"
|
"code.gitea.io/tea/cmd/pulls"
|
||||||
"code.gitea.io/tea/modules/context"
|
"code.gitea.io/tea/modules/context"
|
||||||
|
"code.gitea.io/tea/modules/interact"
|
||||||
"code.gitea.io/tea/modules/print"
|
"code.gitea.io/tea/modules/print"
|
||||||
"code.gitea.io/tea/modules/utils"
|
"code.gitea.io/tea/modules/utils"
|
||||||
|
|
||||||
@ -23,10 +23,15 @@ var CmdPulls = cli.Command{
|
|||||||
Aliases: []string{"pull", "pr"},
|
Aliases: []string{"pull", "pr"},
|
||||||
Category: catEntities,
|
Category: catEntities,
|
||||||
Usage: "Manage and checkout pull requests",
|
Usage: "Manage and checkout pull requests",
|
||||||
Description: `Manage and checkout pull requests`,
|
Description: `Lists PRs when called without argument. If PR index is provided, will show it in detail.`,
|
||||||
ArgsUsage: "[<pull index>]",
|
ArgsUsage: "[<pull index>]",
|
||||||
Action: runPulls,
|
Action: runPulls,
|
||||||
Flags: flags.IssuePRFlags,
|
Flags: append([]cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "comments",
|
||||||
|
Usage: "Wether to display comments (will prompt if not provided & run interactively)",
|
||||||
|
},
|
||||||
|
}, pulls.CmdPullsList.Flags...),
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
&pulls.CmdPullsList,
|
&pulls.CmdPullsList,
|
||||||
&pulls.CmdPullsCheckout,
|
&pulls.CmdPullsCheckout,
|
||||||
@ -72,5 +77,13 @@ func runPullDetail(cmd *cli.Context, index string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
print.PullDetails(pr, reviews, ci)
|
print.PullDetails(pr, reviews, ci)
|
||||||
|
|
||||||
|
if pr.Comments > 0 {
|
||||||
|
err = interact.ShowCommentsMaybeInteractive(ctx, idx, pr.Comments)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error loading comments: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package times
|
package times
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -59,7 +58,6 @@ func RunTimesList(cmd *cli.Context) error {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
user := ctx.Args().First()
|
user := ctx.Args().First()
|
||||||
fmt.Println(ctx.Command.ArgsUsage)
|
|
||||||
if user == "" {
|
if user == "" {
|
||||||
// get all tracked times on the repo
|
// get all tracked times on the repo
|
||||||
times, _, err = client.GetRepoTrackedTimes(ctx.Owner, ctx.Repo)
|
times, _, err = client.GetRepoTrackedTimes(ctx.Owner, ctx.Repo)
|
||||||
|
1
main.go
1
main.go
@ -44,6 +44,7 @@ func main() {
|
|||||||
&cmd.CmdTrackedTimes,
|
&cmd.CmdTrackedTimes,
|
||||||
&cmd.CmdOrgs,
|
&cmd.CmdOrgs,
|
||||||
&cmd.CmdRepos,
|
&cmd.CmdRepos,
|
||||||
|
&cmd.CmdAddComment,
|
||||||
|
|
||||||
&cmd.CmdOpen,
|
&cmd.CmdOpen,
|
||||||
&cmd.CmdNotifications,
|
&cmd.CmdNotifications,
|
||||||
|
75
modules/interact/comments.go
Normal file
75
modules/interact/comments.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package interact
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
|
"code.gitea.io/tea/modules/context"
|
||||||
|
"code.gitea.io/tea/modules/print"
|
||||||
|
"github.com/AlecAivazis/survey/v2"
|
||||||
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ShowCommentsMaybeInteractive fetches & prints comments, depending on the --comments flag.
|
||||||
|
// If that flag is unset, and output is not piped, prompts the user first.
|
||||||
|
func ShowCommentsMaybeInteractive(ctx *context.TeaContext, idx int64, totalComments int) error {
|
||||||
|
if ctx.Bool("comments") {
|
||||||
|
opts := gitea.ListIssueCommentOptions{ListOptions: ctx.GetListOptions()}
|
||||||
|
c := ctx.Login.Client()
|
||||||
|
comments, _, err := c.ListIssueComments(ctx.Owner, ctx.Repo, idx, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
print.Comments(comments)
|
||||||
|
} else if isInteractive() && !ctx.IsSet("comments") {
|
||||||
|
// if we're interactive, but --comments hasn't been explicitly set to false
|
||||||
|
if err := ShowCommentsPaginated(ctx, idx, totalComments); err != nil {
|
||||||
|
fmt.Printf("error while loading comments: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowCommentsPaginated prompts if issue/pr comments should be shown and continues to do so.
|
||||||
|
func ShowCommentsPaginated(ctx *context.TeaContext, idx int64, totalComments int) error {
|
||||||
|
c := ctx.Login.Client()
|
||||||
|
opts := gitea.ListIssueCommentOptions{ListOptions: ctx.GetListOptions()}
|
||||||
|
prompt := "show comments?"
|
||||||
|
commentsLoaded := 0
|
||||||
|
|
||||||
|
// paginated fetch
|
||||||
|
// NOTE: as of gitea 1.13, pagination is not provided by this endpoint, but handles
|
||||||
|
// this function gracefully anyways.
|
||||||
|
for {
|
||||||
|
loadComments := false
|
||||||
|
confirm := survey.Confirm{Message: prompt, Default: true}
|
||||||
|
if err := survey.AskOne(&confirm, &loadComments); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !loadComments {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if comments, _, err := c.ListIssueComments(ctx.Owner, ctx.Repo, idx, opts); err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(comments) != 0 {
|
||||||
|
print.Comments(comments)
|
||||||
|
commentsLoaded += len(comments)
|
||||||
|
}
|
||||||
|
if commentsLoaded >= totalComments {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
opts.ListOptions.Page++
|
||||||
|
prompt = "load more?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInteractive checks if the output is piped, but NOT if the session is run interactively..
|
||||||
|
func isInteractive() bool {
|
||||||
|
return terminal.IsTerminal(int(os.Stdout.Fd()))
|
||||||
|
}
|
@ -11,6 +11,12 @@ import (
|
|||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PromptMultiline runs a textfield-style prompt and blocks until input was made.
|
||||||
|
func PromptMultiline(message string) (content string, err error) {
|
||||||
|
err = survey.AskOne(&survey.Multiline{Message: message}, &content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// PromptPassword asks for a password and blocks until input was made.
|
// PromptPassword asks for a password and blocks until input was made.
|
||||||
func PromptPassword(name string) (pass string, err error) {
|
func PromptPassword(name string) (pass string, err error) {
|
||||||
promptPW := &survey.Password{Message: name + " password:"}
|
promptPW := &survey.Password{Message: name + " password:"}
|
||||||
|
44
modules/print/comment.go
Normal file
44
modules/print/comment.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package print
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Comments renders a list of comments to stdout
|
||||||
|
func Comments(comments []*gitea.Comment) {
|
||||||
|
var out = make([]string, len(comments))
|
||||||
|
for i, c := range comments {
|
||||||
|
out[i] = formatComment(c)
|
||||||
|
}
|
||||||
|
outputMarkdown(fmt.Sprintf(
|
||||||
|
// this will become a heading by means of the first --- from a comment
|
||||||
|
"Comments\n%s",
|
||||||
|
strings.Join(out, "\n"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment renders a comment to stdout
|
||||||
|
func Comment(c *gitea.Comment) {
|
||||||
|
outputMarkdown(formatComment(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatComment(c *gitea.Comment) string {
|
||||||
|
edited := ""
|
||||||
|
if c.Updated.After(c.Created) {
|
||||||
|
edited = fmt.Sprintf(" *(edited on %s)*", FormatTime(c.Updated))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"---\n\n**@%s** wrote on %s%s:\n\n%s\n",
|
||||||
|
c.Poster.UserName,
|
||||||
|
FormatTime(c.Created),
|
||||||
|
edited,
|
||||||
|
c.Body,
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user