-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #191 from garethjevans/issues
- Loading branch information
Showing
6 changed files
with
623 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package getcmd | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/plumming/dx/pkg/cmd" | ||
"github.com/plumming/dx/pkg/domain" | ||
|
||
"github.com/pkg/errors" | ||
|
||
"github.com/plumming/dx/pkg/util" | ||
|
||
"github.com/jenkins-x/jx-logging/pkg/log" | ||
"github.com/plumming/dx/pkg/table" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type GetIssuesCmd struct { | ||
cmd.CommonCmd | ||
ShowBots bool | ||
ShowHidden bool | ||
Review bool | ||
Quiet bool | ||
Me bool | ||
Raw string | ||
Cmd *cobra.Command | ||
Args []string | ||
} | ||
|
||
func NewGetIssuesCmd() *cobra.Command { | ||
c := &GetIssuesCmd{} | ||
cmd := &cobra.Command{ | ||
Use: "issues", | ||
Short: "Gets your open issues", | ||
Long: "", | ||
Example: `Get a list of open issues: | ||
dx get issues | ||
Get a list of your issues: | ||
dx get issues --me | ||
Get a list of issues requiring review: | ||
dx get issues --review | ||
Get a list of issues with a custom query: | ||
dx get issues --raw is:private | ||
`, | ||
Aliases: []string{"issues", "is"}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
c.Cmd = cmd | ||
c.Args = args | ||
err := c.Run() | ||
if err != nil { | ||
log.Logger().Fatalf("unable to run command: %s", err) | ||
} | ||
}, | ||
Args: cobra.NoArgs, | ||
} | ||
|
||
c.AddOptions(cmd) | ||
|
||
cmd.Flags().BoolVarP(&c.ShowBots, "show-bots", "", false, | ||
"Show bot account PRs (default: false)") | ||
cmd.Flags().BoolVarP(&c.ShowHidden, "show-hidden", "", false, | ||
"Show PRs that are filtered by hidden labels (default: false)") | ||
cmd.Flags().BoolVarP(&c.Review, "review", "", false, | ||
"Show PRs that are ready for review") | ||
cmd.Flags().BoolVarP(&c.Quiet, "quiet", "", false, | ||
"Hide the column headings") | ||
cmd.Flags().BoolVarP(&c.Me, "me", "m", false, | ||
"Show all PRs that are created by the author") | ||
|
||
cmd.Flags().StringVarP(&c.Raw, "raw", "", "", | ||
"Additional raw search parameters to use when querying") | ||
|
||
return cmd | ||
} | ||
|
||
func (c *GetIssuesCmd) Run() error { | ||
d := domain.NewGetIssues() | ||
d.ShowHidden = c.ShowHidden | ||
d.ShowBots = c.ShowBots | ||
d.Me = c.Me | ||
d.Review = c.Review | ||
d.Raw = c.Raw | ||
|
||
err := d.Validate() | ||
if err != nil { | ||
return errors.Wrap(err, "validate failed") | ||
} | ||
|
||
err = d.Run() | ||
if err != nil { | ||
return errors.Wrap(err, "run failed") | ||
} | ||
|
||
if c.Query != "" { | ||
fmt.Println(c.Filter(d.Issues)) | ||
return nil | ||
} | ||
|
||
table := table.NewTable(c.Cmd.OutOrStdout()) | ||
|
||
pullURL := "" | ||
if !c.Quiet { | ||
table.AddRow( | ||
"Issue#", | ||
"Author", | ||
"Title", | ||
"Age", | ||
"Labels", | ||
) | ||
} | ||
|
||
for _, pr := range d.Issues { | ||
if pullURL != pr.IssueString() { | ||
table.AddRow(fmt.Sprintf("# %s", util.ColorAnswer(pr.IssueString()))) | ||
pullURL = pr.IssueString() | ||
} | ||
table.AddRow( | ||
util.ColorInfo(fmt.Sprintf("#%d", pr.Number)), | ||
pr.Author.Login, | ||
pr.ColoredTitle(), | ||
util.SafeTime(&pr.CreatedAt), | ||
pr.LabelsString(), | ||
) | ||
} | ||
|
||
table.Render() | ||
|
||
if len(d.Issues) > 0 { | ||
fmt.Printf("\nDisplaying %d Issue(s)\n", len(d.Issues)) | ||
} | ||
|
||
if (d.FilteredBotAccounts + d.FilteredLabels) > 0 { | ||
flags := []string{} | ||
if d.FilteredBotAccounts > 0 { | ||
flags = append(flags, "--show-bots") | ||
} | ||
if d.FilteredLabels > 0 { | ||
flags = append(flags, "--show-hidden") | ||
} | ||
fmt.Printf("\nFiltered %d Issues, use %s to view them\n", (d.FilteredBotAccounts + d.FilteredLabels), strings.Join(flags, ", ")) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package domain | ||
|
||
import ( | ||
"fmt" | ||
"sort" | ||
"strings" | ||
"time" | ||
|
||
"github.com/plumming/dx/pkg/config" | ||
|
||
"github.com/plumming/dx/pkg/pr" | ||
|
||
"github.com/jenkins-x/jx-logging/pkg/log" | ||
"github.com/plumming/dx/pkg/cmd" | ||
) | ||
|
||
var ( | ||
getIssuesQuery = `{ | ||
search(query: "is:issue is:open %s", type: ISSUE, first: %d) { | ||
nodes { | ||
... on Issue { | ||
number | ||
title | ||
url | ||
createdAt | ||
closed | ||
author { | ||
login | ||
} | ||
repository { | ||
nameWithOwner | ||
} | ||
labels(first: 10) { | ||
nodes { | ||
name | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}` | ||
) | ||
|
||
// GetIssues defines get pull issues response. | ||
type GetIssues struct { | ||
cmd.CommonOptions | ||
ShowBots bool | ||
ShowHidden bool | ||
Me bool | ||
Review bool | ||
Raw string | ||
Issues []pr.Issue | ||
FilteredLabels int | ||
FilteredBotAccounts int | ||
} | ||
|
||
// IssueData. | ||
type IssueData struct { | ||
Search IssueSearch `json:"search"` | ||
} | ||
|
||
// IssueSearch. | ||
type IssueSearch struct { | ||
Issues []pr.Issue `json:"nodes"` | ||
} | ||
|
||
// NewGetIssues. | ||
func NewGetIssues() *GetIssues { | ||
g := &GetIssues{} | ||
return g | ||
} | ||
|
||
// Validate input. | ||
func (g *GetIssues) Validate() error { | ||
return nil | ||
} | ||
|
||
// Run the cmd. | ||
func (g *GetIssues) Run() error { | ||
cfg, err := g.DxConfig() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var issues []pr.Issue | ||
|
||
for _, host := range cfg.GetConfiguredServers() { | ||
i, err := g.GetIssuesForHost(host, cfg, getIssuesQuery) | ||
if err != nil { | ||
return err | ||
} | ||
issues = append(issues, i...) | ||
} | ||
|
||
sort.Sort(pr.ByIssuesString(issues)) | ||
|
||
var issuesToReturn []pr.Issue | ||
|
||
filteredOnLabels := 0 | ||
filteredOnAccounts := 0 | ||
|
||
for _, issue := range issues { | ||
if issue.Display() { | ||
if g.filterOnLabels(issue, cfg.GetHiddenLabels()) { | ||
filteredOnLabels++ | ||
} else if g.filterOnAccounts(issue, cfg.GetBotAccounts()) { | ||
filteredOnAccounts++ | ||
} else { | ||
issuesToReturn = append(issuesToReturn, issue) | ||
} | ||
} | ||
} | ||
|
||
log.Logger().Debugf("Filtered %d/%d Issue(s)", filteredOnLabels, filteredOnAccounts) | ||
|
||
g.Issues = issuesToReturn | ||
g.FilteredLabels = filteredOnLabels | ||
g.FilteredBotAccounts = filteredOnAccounts | ||
|
||
return nil | ||
} | ||
|
||
func (g *GetIssues) GetIssuesForHost(host string, cfg config.Config, query string) ([]pr.Issue, error) { | ||
client, err := g.GithubClient() | ||
if err != nil { | ||
return nil, err | ||
} | ||
currentUser, err := GetCurrentUser(client, host) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var queryString string | ||
if g.Raw != "" { | ||
queryString = g.Raw | ||
} else if g.Me { | ||
orgs, err := GetOrgsForUser(client, host) | ||
if err != nil { | ||
return nil, err | ||
} | ||
log.Logger().Debugf("User is a member of %s organisations", orgs) | ||
|
||
userQuery := "user:" + strings.Join(orgs, " user:") | ||
log.Logger().Debugf("User '%s'", userQuery) | ||
|
||
queryString = fmt.Sprintf("author:%s %s", currentUser, userQuery) | ||
} else if g.Review { | ||
queryString = fmt.Sprintf("review-requested:%s", currentUser) | ||
} else { | ||
queryString = strings.Join(cfg.GetReposToQuery(host), " ") | ||
} | ||
|
||
if cfg.GetMaxAgeOfPRs() != -1 { | ||
dateString := time.Now().AddDate(0, 0, -1*cfg.GetMaxAgeOfPRs()).Format("2006-01-02") | ||
queryString = queryString + " created:>" + dateString | ||
} | ||
|
||
queryToRun := fmt.Sprintf(query, queryString, cfg.GetMaxNumberOfPRs()) | ||
log.Logger().Debugf("running query\n%s", queryToRun) | ||
|
||
data := IssueData{} | ||
err = client.GraphQL(host, queryToRun, nil, &data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return data.Search.Issues, nil | ||
} | ||
|
||
func (g *GetIssues) filterOnAccounts(pr pr.Issue, botAccounts []string) bool { | ||
for _, botAccount := range botAccounts { | ||
if pr.Author.Login == botAccount { | ||
return !g.ShowBots | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func (g *GetIssues) filterOnLabels(pr pr.Issue, hiddenLabels []string) bool { | ||
for _, label := range hiddenLabels { | ||
if pr.HasLabel(label) { | ||
return !g.ShowHidden | ||
} | ||
} | ||
return false | ||
} |
Oops, something went wrong.