sip/cmd/issues.go
John Olheiser 5ecbcde518
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Change to vanity URL (#37)
Fix YAML

New changes, generate docs, and add Drone for main

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Merge branch 'master' of gitea.com:jolheiser/sip into vanity

Change to vanity URL

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: jolheiser <john.olheiser@gmail.com>
Reviewed-on: #37
2020-09-21 19:21:07 +00:00

186 lines
4.3 KiB
Go

package cmd
import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"go.jolheiser.com/sip/csv"
"go.jolheiser.com/sip/flag"
"go.jolheiser.com/sip/markdown"
"go.jolheiser.com/sip/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 at `PATH`",
},
},
}
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(false)
if err != nil {
return nil, err
}
typ := "issues"
if pulls {
typ = "pulls"
}
issues, err := queryIssues(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(client *gitea.Client, pulls bool) ([]*gitea.Issue, error) {
owner, repo, err := askOwnerRepo()
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() (string, string, error) {
// If --owner or --repo was set, assume the user knows where they are searching
if flag.OwnerRepoCtxSet {
return flag.Owner, flag.Repo, nil
}
question := []*survey.Question{
{
Name: "repo",
Prompt: &survey.Input{Message: "Full repository name", Default: flag.FullName()},
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
}