mirror of
https://gitea.com/jolheiser/sip
synced 2024-11-26 07:33:48 +01:00
448e12ce38
Ran imp Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: jolheiser <john.olheiser@gmail.com> Reviewed-on: https://gitea.com/jolheiser/sip/pulls/17
181 lines
4.2 KiB
Go
181 lines
4.2 KiB
Go
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"gitea.com/jolheiser/sip/modules/csv"
|
|
"gitea.com/jolheiser/sip/modules/markdown"
|
|
"gitea.com/jolheiser/sip/modules/sdk"
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
"github.com/AlecAivazis/survey/v2"
|
|
"github.com/urfave/cli/v2"
|
|
"go.jolheiser.com/beaver"
|
|
"go.jolheiser.com/beaver/color"
|
|
)
|
|
|
|
var Issues = cli.Command{
|
|
Name: "issues",
|
|
Aliases: []string{"issue"},
|
|
Usage: "Commands for interacting with issues",
|
|
Action: doIssuesSearch,
|
|
Subcommands: []*cli.Command{
|
|
&IssuesCreate,
|
|
},
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "csv",
|
|
Usage: "Output results to a CSV file",
|
|
},
|
|
},
|
|
}
|
|
|
|
func doIssuesSearch(ctx *cli.Context) error {
|
|
if _, err := issuesSearch(ctx, false); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func issuesSearch(ctx *cli.Context, pulls bool) (*gitea.Issue, error) {
|
|
client, err := getClient(ctx, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
typ := "issues"
|
|
if pulls {
|
|
typ = "pulls"
|
|
}
|
|
issues, err := queryIssues(ctx, client, pulls)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(issues) == 0 {
|
|
beaver.Errorf("No %s found!", typ)
|
|
return nil, nil
|
|
}
|
|
|
|
if ctx.String("csv") != "" {
|
|
fi, err := os.Create(ctx.String("csv"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := fi.WriteString(csv.Issues(issues)); err != nil {
|
|
return nil, err
|
|
}
|
|
fmt.Println(color.FgCyan.Formatf("Matching %s were exported to", typ), color.Info.Format(ctx.String("csv")))
|
|
return nil, fi.Close()
|
|
}
|
|
|
|
issueMap := make(map[string]*gitea.Issue)
|
|
for _, issue := range issues {
|
|
index := color.New(color.FgCyan).Format("#" + strconv.Itoa(int(issue.Index)))
|
|
title := color.New(color.FgYellow).Format(issue.Title)
|
|
state := color.New(color.FgGreen).Format("[open]")
|
|
if issue.PullRequest != nil && issue.PullRequest.HasMerged {
|
|
state = color.New(color.FgMagenta).Format("[merged]")
|
|
} else if issue.State == gitea.StateClosed {
|
|
state = color.New(color.FgRed).Format("[closed]")
|
|
}
|
|
lbls := make([]string, len(issue.Labels))
|
|
for idx, label := range issue.Labels {
|
|
lbls[idx] = label.Name
|
|
}
|
|
var labels string
|
|
if len(lbls) > 0 {
|
|
labels = color.New(color.FgHiBlack).Format("(" + strings.Join(lbls, ", ") + ")")
|
|
}
|
|
issueMap[fmt.Sprintf("%s %s %s %s", index, state, title, labels)] = issue
|
|
}
|
|
|
|
list := make([]string, 0)
|
|
for key := range issueMap {
|
|
list = append(list, key)
|
|
}
|
|
sel := &survey.Select{Options: list, Message: "Matching " + typ}
|
|
var selection string
|
|
if err := survey.AskOne(sel, &selection); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
body, err := markdown.Render(issueMap[selection].Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fmt.Println(body)
|
|
return issueMap[selection], nil
|
|
}
|
|
|
|
func queryIssues(ctx *cli.Context, client *gitea.Client, pulls bool) ([]*gitea.Issue, error) {
|
|
owner, repo, err := askOwnerRepo(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
question := &survey.Input{Message: "Search query"}
|
|
var answer string
|
|
if err := survey.AskOne(question, &answer); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
filter := sdk.NewIssueFilter(answer)
|
|
opts := gitea.ListIssueOption{KeyWord: filter.Query, State: "all"}
|
|
issues, err := sdk.GetIssues(client, owner, repo, opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
filtered := make([]*gitea.Issue, 0)
|
|
for _, issue := range issues {
|
|
// Filter out issues if searching PRs and vice-versa
|
|
if (pulls && issue.PullRequest == nil) ||
|
|
(!pulls && issue.PullRequest != nil) {
|
|
continue
|
|
}
|
|
|
|
if !filter.Match(issue) {
|
|
continue
|
|
}
|
|
|
|
filtered = append(filtered, issue)
|
|
}
|
|
|
|
return filtered, nil
|
|
}
|
|
|
|
func askOwnerRepo(ctx *cli.Context) (string, string, error) {
|
|
question := []*survey.Question{
|
|
{
|
|
Name: "repo",
|
|
Prompt: &survey.Input{Message: "Full repository name", Default: fullName(ctx)},
|
|
Validate: validateFullName,
|
|
},
|
|
}
|
|
answer := struct {
|
|
Repo string
|
|
}{}
|
|
|
|
if err := survey.Ask(question, &answer); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
ownerRepo := strings.Split(answer.Repo, "/")
|
|
return ownerRepo[0], ownerRepo[1], nil
|
|
}
|
|
|
|
func validateFullName(ans interface{}) error {
|
|
fullName := ans.(string)
|
|
ownerRepo := strings.Split(fullName, "/")
|
|
if len(ownerRepo) != 2 {
|
|
return errors.New("full repo name should be in form `owner/repo`")
|
|
}
|
|
return nil
|
|
}
|