Merge pull request #745 from doi-t/add-metadata-to-view
Add relevant metadata to issue view in CLI
This commit is contained in:
commit
c670049ce7
6 changed files with 230 additions and 64 deletions
|
|
@ -18,6 +18,7 @@ type IssuesAndTotalCount struct {
|
|||
TotalCount int
|
||||
}
|
||||
|
||||
// Ref. https://developer.github.com/v4/object/issue/
|
||||
type Issue struct {
|
||||
Number int
|
||||
Title string
|
||||
|
|
@ -32,15 +33,32 @@ type Issue struct {
|
|||
Author struct {
|
||||
Login string
|
||||
}
|
||||
|
||||
Labels struct {
|
||||
Nodes []IssueLabel
|
||||
Assignees struct {
|
||||
Nodes []struct {
|
||||
Login string
|
||||
}
|
||||
TotalCount int
|
||||
}
|
||||
}
|
||||
|
||||
type IssueLabel struct {
|
||||
Name string
|
||||
Labels struct {
|
||||
Nodes []struct {
|
||||
Name string
|
||||
}
|
||||
TotalCount int
|
||||
}
|
||||
ProjectCards struct {
|
||||
Nodes []struct {
|
||||
Project struct {
|
||||
Name string
|
||||
}
|
||||
Column struct {
|
||||
Name string
|
||||
}
|
||||
}
|
||||
TotalCount int
|
||||
}
|
||||
Milestone struct {
|
||||
Title string
|
||||
}
|
||||
}
|
||||
|
||||
const fragments = `
|
||||
|
|
@ -287,14 +305,35 @@ func IssueByNumber(client *Client, repo ghrepo.Interface, number int) (*Issue, e
|
|||
comments {
|
||||
totalCount
|
||||
}
|
||||
labels(first: 3) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
number
|
||||
url
|
||||
createdAt
|
||||
assignees(first: 100) {
|
||||
nodes {
|
||||
login
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
labels(first: 100) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
projectCards(first: 100) {
|
||||
nodes {
|
||||
project {
|
||||
name
|
||||
}
|
||||
column {
|
||||
name
|
||||
}
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
milestone{
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
|
|
|||
|
|
@ -259,8 +259,9 @@ func printIssuePreview(out io.Writer, issue *api.Issue) error {
|
|||
now := time.Now()
|
||||
ago := now.Sub(issue.CreatedAt)
|
||||
|
||||
// Header (Title and State)
|
||||
fmt.Fprintln(out, utils.Bold(issue.Title))
|
||||
fmt.Fprintf(out, "%s", issueStateTitleWithColor(issue.State))
|
||||
fmt.Fprint(out, issueStateTitleWithColor(issue.State))
|
||||
fmt.Fprintln(out, utils.Gray(fmt.Sprintf(
|
||||
" • %s opened %s • %s",
|
||||
issue.Author.Login,
|
||||
|
|
@ -268,6 +269,26 @@ func printIssuePreview(out io.Writer, issue *api.Issue) error {
|
|||
utils.Pluralize(issue.Comments.TotalCount, "comment"),
|
||||
)))
|
||||
|
||||
// Metadata
|
||||
fmt.Fprintln(out)
|
||||
if assignees := issueAssigneeList(*issue); assignees != "" {
|
||||
fmt.Fprint(out, utils.Bold("Assignees: "))
|
||||
fmt.Fprintln(out, assignees)
|
||||
}
|
||||
if labels := issueLabelList(*issue); labels != "" {
|
||||
fmt.Fprint(out, utils.Bold("Labels: "))
|
||||
fmt.Fprintln(out, labels)
|
||||
}
|
||||
if projects := issueProjectList(*issue); projects != "" {
|
||||
fmt.Fprint(out, utils.Bold("Projects: "))
|
||||
fmt.Fprintln(out, projects)
|
||||
}
|
||||
if issue.Milestone.Title != "" {
|
||||
fmt.Fprint(out, utils.Bold("Milestone: "))
|
||||
fmt.Fprintln(out, issue.Milestone.Title)
|
||||
}
|
||||
|
||||
// Body
|
||||
if issue.Body != "" {
|
||||
fmt.Fprintln(out)
|
||||
md, err := utils.RenderMarkdown(issue.Body)
|
||||
|
|
@ -275,9 +296,10 @@ func printIssuePreview(out io.Writer, issue *api.Issue) error {
|
|||
return err
|
||||
}
|
||||
fmt.Fprintln(out, md)
|
||||
fmt.Fprintln(out)
|
||||
}
|
||||
fmt.Fprintln(out)
|
||||
|
||||
// Footer
|
||||
fmt.Fprintf(out, utils.Gray("View this issue on GitHub: %s\n"), issue.URL)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -422,7 +444,7 @@ func printIssues(w io.Writer, prefix string, totalCount int, issues []api.Issue)
|
|||
issueNum = "#" + issueNum
|
||||
}
|
||||
issueNum = prefix + issueNum
|
||||
labels := labelList(issue)
|
||||
labels := issueLabelList(issue)
|
||||
if labels != "" && table.IsTTY() {
|
||||
labels = fmt.Sprintf("(%s)", labels)
|
||||
}
|
||||
|
|
@ -441,7 +463,24 @@ func printIssues(w io.Writer, prefix string, totalCount int, issues []api.Issue)
|
|||
}
|
||||
}
|
||||
|
||||
func labelList(issue api.Issue) string {
|
||||
func issueAssigneeList(issue api.Issue) string {
|
||||
if len(issue.Assignees.Nodes) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
AssigneeNames := make([]string, 0, len(issue.Assignees.Nodes))
|
||||
for _, assignee := range issue.Assignees.Nodes {
|
||||
AssigneeNames = append(AssigneeNames, assignee.Login)
|
||||
}
|
||||
|
||||
list := strings.Join(AssigneeNames, ", ")
|
||||
if issue.Assignees.TotalCount > len(issue.Assignees.Nodes) {
|
||||
list += ", …"
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func issueLabelList(issue api.Issue) string {
|
||||
if len(issue.Labels.Nodes) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
|
@ -458,6 +497,23 @@ func labelList(issue api.Issue) string {
|
|||
return list
|
||||
}
|
||||
|
||||
func issueProjectList(issue api.Issue) string {
|
||||
if len(issue.ProjectCards.Nodes) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
projectNames := make([]string, 0, len(issue.ProjectCards.Nodes))
|
||||
for _, project := range issue.ProjectCards.Nodes {
|
||||
projectNames = append(projectNames, fmt.Sprintf("%s (%s)", project.Project.Name, project.Column.Name))
|
||||
}
|
||||
|
||||
list := strings.Join(projectNames, ", ")
|
||||
if issue.ProjectCards.TotalCount > len(issue.ProjectCards.Nodes) {
|
||||
list += ", …"
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func displayURL(urlStr string) string {
|
||||
u, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -292,26 +292,30 @@ func TestIssueView_Preview(t *testing.T) {
|
|||
fixture string
|
||||
expectedOutputs []string
|
||||
}{
|
||||
"Open issue": {
|
||||
"Open issue without metadata": {
|
||||
ownerRepo: "master",
|
||||
command: "issue view 123",
|
||||
fixture: "../test/fixtures/issueView_preview.json",
|
||||
expectedOutputs: []string{
|
||||
"ix of coins",
|
||||
"Open • marseilles opened about 292 years ago • 9 comments",
|
||||
"bold story",
|
||||
"View this issue on GitHub: https://github.com/OWNER/REPO/issues/123",
|
||||
`ix of coins`,
|
||||
`Open • marseilles opened about 292 years ago • 9 comments`,
|
||||
`bold story`,
|
||||
`View this issue on GitHub: https://github.com/OWNER/REPO/issues/123`,
|
||||
},
|
||||
},
|
||||
"Open issue with no label": {
|
||||
"Open issue with metadata": {
|
||||
ownerRepo: "master",
|
||||
command: "issue view 123",
|
||||
fixture: "../test/fixtures/issueView_previewNoLabel.json",
|
||||
fixture: "../test/fixtures/issueView_previewWithMetadata.json",
|
||||
expectedOutputs: []string{
|
||||
"ix of coins",
|
||||
"Open • marseilles opened about 292 years ago • 9 comments",
|
||||
"bold story",
|
||||
"View this issue on GitHub: https://github.com/OWNER/REPO/issues/123",
|
||||
`ix of coins`,
|
||||
`Open • marseilles opened about 292 years ago • 9 comments`,
|
||||
`Assignees: marseilles, monaco\n`,
|
||||
`Labels: one, two, three, four, five\n`,
|
||||
`Projects: Project 1 \(column A\), Project 2 \(column B\), Project 3 \(column C\)\n`,
|
||||
`Milestone: uluru\n`,
|
||||
`bold story`,
|
||||
`View this issue on GitHub: https://github.com/OWNER/REPO/issues/123`,
|
||||
},
|
||||
},
|
||||
"Open issue with empty body": {
|
||||
|
|
@ -319,9 +323,9 @@ func TestIssueView_Preview(t *testing.T) {
|
|||
command: "issue view 123",
|
||||
fixture: "../test/fixtures/issueView_previewWithEmptyBody.json",
|
||||
expectedOutputs: []string{
|
||||
"ix of coins",
|
||||
"Open • marseilles opened about 292 years ago • 9 comments",
|
||||
"View this issue on GitHub: https://github.com/OWNER/REPO/issues/123",
|
||||
`ix of coins`,
|
||||
`Open • marseilles opened about 292 years ago • 9 comments`,
|
||||
`View this issue on GitHub: https://github.com/OWNER/REPO/issues/123`,
|
||||
},
|
||||
},
|
||||
"Closed issue": {
|
||||
|
|
@ -329,10 +333,10 @@ func TestIssueView_Preview(t *testing.T) {
|
|||
command: "issue view 123",
|
||||
fixture: "../test/fixtures/issueView_previewClosedState.json",
|
||||
expectedOutputs: []string{
|
||||
"ix of coins",
|
||||
"Closed • marseilles opened about 292 years ago • 9 comments",
|
||||
"bold story",
|
||||
"View this issue on GitHub: https://github.com/OWNER/REPO/issues/123",
|
||||
`ix of coins`,
|
||||
`Closed • marseilles opened about 292 years ago • 9 comments`,
|
||||
`bold story`,
|
||||
`View this issue on GitHub: https://github.com/OWNER/REPO/issues/123`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
18
test/fixtures/issueView_preview.json
vendored
18
test/fixtures/issueView_preview.json
vendored
|
|
@ -11,12 +11,20 @@
|
|||
"author": {
|
||||
"login": "marseilles"
|
||||
},
|
||||
"assignees": {
|
||||
"nodes": [],
|
||||
"totalcount": 0
|
||||
},
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "tarot"
|
||||
}
|
||||
]
|
||||
"nodes": [],
|
||||
"totalcount": 0
|
||||
},
|
||||
"projectcards": {
|
||||
"nodes": [],
|
||||
"totalcount": 0
|
||||
},
|
||||
"milestone": {
|
||||
"title": ""
|
||||
},
|
||||
"comments": {
|
||||
"totalCount": 9
|
||||
|
|
|
|||
25
test/fixtures/issueView_previewNoLabel.json
vendored
25
test/fixtures/issueView_previewNoLabel.json
vendored
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"data": {
|
||||
"repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issue": {
|
||||
"number": 123,
|
||||
"body": "**bold story**",
|
||||
"title": "ix of coins",
|
||||
"state": "OPEN",
|
||||
"created_at": "2011-01-26T19:01:12Z",
|
||||
"author": {
|
||||
"login": "marseilles"
|
||||
},
|
||||
"labels": {
|
||||
"nodes": [
|
||||
]
|
||||
},
|
||||
"comments": {
|
||||
"totalCount": 9
|
||||
},
|
||||
"url": "https://github.com/OWNER/REPO/issues/123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
test/fixtures/issueView_previewWithMetadata.json
vendored
Normal file
84
test/fixtures/issueView_previewWithMetadata.json
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"data": {
|
||||
"repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issue": {
|
||||
"number": 123,
|
||||
"body": "**bold story**",
|
||||
"title": "ix of coins",
|
||||
"state": "OPEN",
|
||||
"created_at": "2011-01-26T19:01:12Z",
|
||||
"author": {
|
||||
"login": "marseilles"
|
||||
},
|
||||
"assignees": {
|
||||
"nodes": [
|
||||
{
|
||||
"login": "marseilles"
|
||||
},
|
||||
{
|
||||
"login": "monaco"
|
||||
}
|
||||
],
|
||||
"totalcount": 2
|
||||
},
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "one"
|
||||
},
|
||||
{
|
||||
"name": "two"
|
||||
},
|
||||
{
|
||||
"name": "three"
|
||||
},
|
||||
{
|
||||
"name": "four"
|
||||
},
|
||||
{
|
||||
"name": "five"
|
||||
}
|
||||
],
|
||||
"totalcount": 5
|
||||
},
|
||||
"projectcards": {
|
||||
"nodes": [
|
||||
{
|
||||
"project": {
|
||||
"name": "Project 1"
|
||||
},
|
||||
"column": {
|
||||
"name": "column A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"project": {
|
||||
"name": "Project 2"
|
||||
},
|
||||
"column": {
|
||||
"name": "column B"
|
||||
}
|
||||
},
|
||||
{
|
||||
"project": {
|
||||
"name": "Project 3"
|
||||
},
|
||||
"column": {
|
||||
"name": "column C"
|
||||
}
|
||||
}
|
||||
],
|
||||
"totalcount": 3
|
||||
},
|
||||
"milestone": {
|
||||
"title": "uluru"
|
||||
},
|
||||
"comments": {
|
||||
"totalcount": 9
|
||||
},
|
||||
"url": "https://github.com/OWNER/REPO/issues/123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue