Skip to content

Commit

Permalink
Merge pull request #33 from benmatselby/search-table
Browse files Browse the repository at this point in the history
Provide a `--format` option for the search command.
  • Loading branch information
benmatselby authored Nov 8, 2019
2 parents 1f25a5a + b50a1ff commit 4674d5d
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

## next

## 2.2.0

- Addition of a `search` command. This allows you to run JQL either via the configuration file (you specify `--template` to find the correct template in the config file), or the CLI `--query` option. It displays the ID, and the title of the issues it finds. If `fields.story_point_field` is defined in your configuration, the output will also include the Story Point value.
- Option of `--format` on the search command, that allows you to either get a list of issues, or a table view of data. When coupled with the story point field, you can see a tablular view of: Total issues, Total story points, Total not story pointed.

## 2.1.0

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ boards:
- Review
- Done

fields:
story_point_field: customfield_10911

templates:
all-open:
query: "project = 'My Project' AND status != Completed ORDER BY Summary"
Expand Down
50 changes: 48 additions & 2 deletions cmd/search/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io"
"os"
"text/tabwriter"

goJira "github.com/andygrunwald/go-jira"
"github.com/benmatselby/walter/jira"
Expand All @@ -19,6 +20,7 @@ const (
// CommandOptions defines the options available for searching
type CommandOptions struct {
Args []string
Format string
MaxResults int
Query string
Template string
Expand All @@ -43,6 +45,7 @@ func NewSearchCommand(client jira.API) *cobra.Command {
}

flags := cmd.Flags()
flags.StringVarP(&opts.Format, "format", "f", "list", "The format of the output: list, table")
flags.IntVar(&opts.MaxResults, "max-results", DefaultMaxResults, "The amount of records to display")
flags.StringVarP(&opts.Query, "query", "q", "", "The JQL you want to run")
flags.StringVarP(&opts.Template, "template", "t", "", "The name of the template that as the JQL you want to run")
Expand Down Expand Up @@ -79,6 +82,51 @@ func QueryIssues(client jira.API, opts CommandOptions, w io.Writer) error {
return err
}

if opts.Format == "table" {
renderTable(issues, w)
} else {
renderList(issues, w)
}

return nil
}

func renderTable(issues []goJira.Issue, w io.Writer) {
tw := tabwriter.NewWriter(w, 0, 1, 1, ' ', 0)
fmt.Fprintf(tw, "%s\t%s\n", "Metric", "Count")
fmt.Fprintf(tw, "%s\t%s\n", "------", "-----")
totalPoints := 0
totalUnestimated := 0

pointsUsed := false
if viper.IsSet("fields.story_point_field") {
pointsUsed = true
}

for _, issue := range issues {
if pointsUsed {
value := issue.Fields.Unknowns[viper.GetString("fields.story_point_field")]
if value != nil {
totalPoints += int(value.(float64))
} else {
totalUnestimated++
}
}
}

fmt.Fprintf(tw, "%s\t%d\n", "Issues", len(issues))

if pointsUsed {
fmt.Fprintf(tw, "%s\t%d\n", "Points", totalPoints)
fmt.Fprintf(tw, "%s\t%d\n", "Not pointed", totalUnestimated)
}

fmt.Fprintf(tw, "%s\t%s\n", "------", "-----")

tw.Flush()
}

func renderList(issues []goJira.Issue, w io.Writer) {
for _, issue := range issues {
storyPoint := ""
if viper.IsSet("fields.story_point_field") {
Expand All @@ -89,6 +137,4 @@ func QueryIssues(client jira.API, opts CommandOptions, w io.Writer) error {
}
fmt.Fprintf(w, "* %s - %s%s\n", issue.Key, storyPoint, issue.Fields.Summary)
}

return nil
}
23 changes: 23 additions & 0 deletions cmd/search/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestCommandOptions(t *testing.T) {
func TestQueryIssues(t *testing.T) {
tt := []struct {
name string
format string
query string
template string
maxResults int
Expand All @@ -48,6 +49,11 @@ func TestQueryIssues(t *testing.T) {
{name: "can handle an error from the search", query: "status != Completed", maxResults: 10, expectedMaxResults: 10, expectedQuery: "status != Completed", output: "* 101 - Issue 1\n", err: errors.New("boom")},
{name: "can handle the fact we dont pass template or query", query: "", expectedMaxResults: 43, err: errors.New("please use --query or --template to search")},
{name: "can handle the fact a template may not be defined", template: "undefined-flim-flam", expectedMaxResults: 43, err: errors.New("undefined-flim-flam is not defined")},
{name: "can return a table of issues via query option", query: "status != Completed", format: "table", maxResults: 10, expectedMaxResults: 10, expectedQuery: "status != Completed", output: `Metric Count
------ -----
Issues 1
------ -----
`, err: nil},
}

for _, tc := range tt {
Expand Down Expand Up @@ -75,6 +81,7 @@ func TestQueryIssues(t *testing.T) {
issues = append(issues, jiraIssues)

opts := search.CommandOptions{
Format: tc.format,
MaxResults: tc.maxResults,
Query: tc.query,
Template: tc.template,
Expand Down Expand Up @@ -112,12 +119,27 @@ func TestQueryIssues(t *testing.T) {
func TestQueryIssuesCanHandleStoryPoints(t *testing.T) {
tt := []struct {
name string
format string
query string
storyPointDefined bool
output string
}{
{name: "can handle the happy path of the story point defined", query: "status != Completed", storyPointDefined: true, output: "* 101 - (15) Issue 1\n"},
{name: "can handle the story point field defined but not value", query: "status != Completed", storyPointDefined: false, output: "* 101 - Issue 1\n"},
{name: "can return a table of issues via query option", query: "status != Completed", format: "table", output: `Metric Count
------ -----
Issues 1
Points 0
Not pointed 1
------ -----
`},
{name: "can return a table of issues via query option", query: "status != Completed", storyPointDefined: true, format: "table", output: `Metric Count
------ -----
Issues 1
Points 15
Not pointed 0
------ -----
`},
}

for _, tc := range tt {
Expand Down Expand Up @@ -152,6 +174,7 @@ func TestQueryIssuesCanHandleStoryPoints(t *testing.T) {
issues = append(issues, jiraIssues)

opts := search.CommandOptions{
Format: tc.format,
MaxResults: 41,
Query: tc.query,
}
Expand Down

0 comments on commit 4674d5d

Please sign in to comment.