提交 c142db3f 编写于 作者: P Pascal Corpet

Use formatter when listing issues.

上级 eafcc383
......@@ -16,7 +16,7 @@ var (
cmdIssue = &Command{
Run: listIssues,
Usage: `
issue [-a <ASSIGNEE>]
issue [-a <ASSIGNEE>] [-s <STATE>] [-f <FORMAT>]
issue create [-m <MESSAGE>|-F <FILE>] [-l <LABELS>]
`,
Long: `Manage GitHub issues for the current project.
......@@ -28,6 +28,30 @@ issue create [-m <MESSAGE>|-F <FILE>] [-l <LABELS>]
-s, --state <STATE>
Display issues with state <STATE> (default: "open").
-f, --format <FORMAT>
Pretty print the contents of the issues using format <FORMAT> (default:
"%sC%>(8)%ih%Creset %t% l%n"). See the "PRETTY FORMATS" section of the
git-log manual for some additional details on how placeholders are used in
format. The available placeholders for issues are:
· %in: the number of the issue.
· %ih: the number of the issue prefixed with #.
· %st: the state of the issue as a text (i.e. "open", "closed").
· %sC: switch color to red if issue is closed or green if issue is open.
· %t: the title of the issue.
· %l: the colored labels of the issue.
· %b: the body of the issue.
· %u: the login of the user that opened the issue.
· %a: the login of the user that the issue is assigned to.
-m, --message <MESSAGE>
Use the first line of <MESSAGE> as issue title, and the rest as issue description.
......@@ -48,6 +72,7 @@ issue create [-m <MESSAGE>|-F <FILE>] [-l <LABELS>]
flagIssueAssignee,
flagIssueState,
flagIssueFormat,
flagIssueMessage,
flagIssueFile string
......@@ -61,6 +86,7 @@ func init() {
cmdIssue.Flag.StringVarP(&flagIssueAssignee, "assignee", "a", "", "ASSIGNEE")
cmdIssue.Flag.StringVarP(&flagIssueState, "state", "s", "", "ASSIGNEE")
cmdIssue.Flag.StringVarP(&flagIssueFormat, "format", "f", "%sC%>(8)%ih%Creset %t% l%n", "FORMAT")
cmdIssue.Use(cmdCreateIssue)
CmdRunner.Use(cmdIssue)
......@@ -97,47 +123,65 @@ func listIssues(cmd *Command, args *Args) {
}
colorize := ui.IsTerminal(os.Stdout)
for _, issue := range issues {
if issue.PullRequest != nil {
continue
}
num := fmt.Sprintf("#%d", issue.Number)
numWidth := len(num)
if colorize {
issueColor := 32
if issue.State == "closed" {
issueColor = 31
}
num = fmt.Sprintf("\033[%dm%s\033[0m", issueColor, num)
}
ui.Printf(formatIssue(issue, flagIssueFormat, colorize))
}
}
ui.Printf("%*s%s %s", maxNumWidth+1-numWidth, "", num, issue.Title)
os.Exit(0)
}
for i, label := range issue.Labels {
color, err := utils.NewColor(label.Color)
if err != nil {
utils.Check(err)
}
func formatIssue(issue github.Issue, format string, colorize bool) string {
var assigneeLogin string
if a := issue.Assignee; a != nil {
assigneeLogin = a.Login
}
textColor := 16
if color.Brightness() < 0.65 {
textColor = 15
}
var stateColorSwitch string
if colorize {
issueColor := 32
if issue.State == "closed" {
issueColor = 31
}
stateColorSwitch = fmt.Sprintf("\033[%dm", issueColor)
}
if i == 0 {
ui.Printf(" ")
}
ui.Printf(" \033[38;5;%d;48;2;%d;%d;%dm %s \033[m", textColor, color.Red, color.Green, color.Blue, label.Name)
}
var labelStrings []string
for _, label := range issue.Labels {
if !colorize {
labelStrings = append(labelStrings, fmt.Sprintf(" %s ", label.Name))
continue
}
color, err := utils.NewColor(label.Color)
if err != nil {
utils.Check(err)
}
ui.Printf("\n")
textColor := 16
if color.Brightness() < 0.65 {
textColor = 15
}
labelStrings = append(labelStrings, fmt.Sprintf("\033[38;5;%d;48;2;%d;%d;%dm %s \033[m", textColor, color.Red, color.Green, color.Blue, label.Name))
}
os.Exit(0)
placeholders := map[string]string{
"in": fmt.Sprintf("%d", issue.Number),
"ih": fmt.Sprintf("#%d", issue.Number),
"st": issue.State,
"sC": stateColorSwitch,
"t": issue.Title,
"l": strings.Join(labelStrings, " "),
"b": issue.Body,
"u": issue.User.Login,
"a": assigneeLogin,
}
return ui.Expand(format, placeholders, colorize)
}
func createIssue(cmd *Command, args *Args) {
......
package commands
import (
"testing"
"github.com/github/hub/github"
)
type formatIssueTest struct {
name string
issue github.Issue
format string
colorize bool
expect string
}
func testFormatIssue(t *testing.T, tests []formatIssueTest) {
for _, test := range tests {
if got := formatIssue(test.issue, test.format, test.colorize); got != test.expect {
t.Errorf("%s: formatIssue(..., %q, %t) = %q, want %q", test.name, test.format, test.colorize, got, test.expect)
}
}
}
func TestFormatIssue(t *testing.T) {
format := "%sC%>(8)%ih%Creset %t% l%n"
testFormatIssue(t, []formatIssueTest{
{
name: "standard usage",
issue: github.Issue{
Number: 42,
Title: "Just an Issue",
State: "open",
User: &github.User{Login: "pcorpet"},
Body: "Body of the\nissue",
Assignee: &github.User{Login: "mislav"},
},
format: format,
colorize: true,
expect: "\033[32m #42\033[m Just an Issue\n",
},
{
name: "closed issue colored differently",
issue: github.Issue{
Number: 42,
Title: "Just an Issue",
State: "closed",
User: &github.User{Login: "pcorpet"},
},
format: format,
colorize: true,
expect: "\033[31m #42\033[m Just an Issue\n",
},
{
name: "labels",
issue: github.Issue{
Number: 42,
Title: "An issue with labels",
State: "open",
User: &github.User{Login: "pcorpet"},
Labels: []github.IssueLabel{
{Name: "bug", Color: "800000"},
{Name: "reproduced", Color: "55ff55"},
},
},
format: format,
colorize: true,
expect: "\033[32m #42\033[m An issue with labels \033[38;5;15;48;2;128;0;0m bug \033[m \033[38;5;16;48;2;85;255;85m reproduced \033[m\n",
},
{
name: "not colorized",
issue: github.Issue{
Number: 42,
Title: "Just an Issue",
State: "open",
User: &github.User{Login: "pcorpet"},
},
format: format,
colorize: false,
expect: " #42 Just an Issue\n",
},
{
name: "labels not colorized",
issue: github.Issue{
Number: 42,
Title: "An issue with labels",
State: "open",
User: &github.User{Login: "pcorpet"},
Labels: []github.IssueLabel{
{Name: "bug", Color: "880000"},
{Name: "reproduced", Color: "55ff55"},
},
},
format: format,
colorize: false,
expect: " #42 An issue with labels bug reproduced \n",
},
})
}
func TestFormatIssue_customFormatString(t *testing.T) {
issue := github.Issue{
Number: 42,
Title: "Just an Issue",
State: "open",
User: &github.User{Login: "pcorpet"},
Body: "Body of the\nissue",
Assignee: &github.User{Login: "mislav"},
Labels: []github.IssueLabel{
{Name: "bug", Color: "880000"},
},
}
testFormatIssue(t, []formatIssueTest{
{
name: "number",
issue: issue,
format: "%in",
colorize: true,
expect: "42",
},
{
name: "hashed number",
issue: issue,
format: "%ih",
colorize: true,
expect: "#42",
},
{
name: "state as text",
issue: issue,
format: "%st",
colorize: true,
expect: "open",
},
{
name: "state as color switch",
issue: issue,
format: "%sC",
colorize: true,
expect: "\033[32m",
},
{
name: "state as color switch non colorized",
issue: issue,
format: "%sC",
colorize: false,
expect: "",
},
{
name: "title",
issue: issue,
format: "%t",
colorize: true,
expect: "Just an Issue",
},
{
name: "label colorized",
issue: issue,
format: "%l",
colorize: true,
expect: "\033[38;5;15;48;2;136;0;0m bug \033[m",
},
{
name: "label not colorized",
issue: issue,
format: "%l",
colorize: false,
expect: " bug ",
},
{
name: "body",
issue: issue,
format: "%b",
colorize: true,
expect: "Body of the\nissue",
},
{
name: "user login",
issue: issue,
format: "%u",
colorize: true,
expect: "pcorpet",
},
{
name: "assignee login",
issue: issue,
format: "%a",
colorize: true,
expect: "mislav",
},
{
name: "assignee login but not assigned",
issue: github.Issue{
State: "open",
User: &github.User{Login: "pcorpet"},
},
format: "%a",
colorize: true,
expect: "",
},
})
}
......@@ -7,19 +7,22 @@ import (
)
// Expand expands a format string using `git log` message syntax.
func Expand(format string, values map[string]string) string {
f := &expander{values: values}
func Expand(format string, values map[string]string, colorize bool) string {
f := &expander{values: values, colorize: colorize}
return f.Expand(format)
}
// An expander is a stateful helper to expand a format string.
type expander struct {
// formatted holds the
// formatted holds the parts of the string that have already been formatted.
formatted []string
// values is the map of values that should be expanded.
values map[string]string
// colorize is a flag to indiciate whether to use colors.
colorize bool
// skipNext is true if the next placeholder is not a placeholder and can be
// output directly as such.
skipNext bool
......@@ -100,7 +103,10 @@ func (f *expander) expandSpecialChar(firstChar byte, format string) (expand stri
case 'C':
for k, v := range colorMap {
if strings.HasPrefix(format, k) {
return "\033[" + v + "m", format[len(k):], true
if f.colorize {
return "\033[" + v + "m", format[len(k):], true
}
return "", format[len(k):], true
}
}
// TODO: Add custom color as specified in color.branch.* options.
......
......@@ -5,15 +5,16 @@ import (
)
type expanderTest struct {
name string
format string
values map[string]string
expect string
name string
format string
values map[string]string
colorize bool
expect string
}
func testExpander(t *testing.T, tests []expanderTest) {
for _, test := range tests {
if got := Expand(test.format, test.values); got != test.expect {
if got := Expand(test.format, test.values, test.colorize); got != test.expect {
t.Errorf("%s: Expand(%q, ...) = %q, want %q", test.name, test.format, got, test.expect)
}
}
......@@ -39,10 +40,18 @@ func TestExpand(t *testing.T) {
expect: "%a %b %",
},
{
name: "Colors",
format: "%Cred%r %Cgreen%g %Cblue%b%Creset normal",
values: map[string]string{"r": "RED", "g": "GREEN", "b": "BLUE"},
expect: "\033[31mRED \033[32mGREEN \033[34mBLUE\033[m normal",
name: "Colors",
format: "%Cred%r %Cgreen%g %Cblue%b%Creset normal",
values: map[string]string{"r": "RED", "g": "GREEN", "b": "BLUE"},
colorize: true,
expect: "\033[31mRED \033[32mGREEN \033[34mBLUE\033[m normal",
},
{
name: "Colors not colorized",
format: "%Cred%r %Cgreen%g %Cblue%b%Creset normal",
values: map[string]string{"r": "RED", "g": "GREEN", "b": "BLUE"},
colorize: false,
expect: "RED GREEN BLUE normal",
},
{
name: "Byte from hex code",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册