зеркало из https://github.com/mislav/hub.git
Add the command `hub issue view <NUMBER>`
This commit adds the subcommand hub issue view, which displays an issue as well as lists its comments underneath.
This commit is contained in:
Родитель
b15d8de5e4
Коммит
6b5997f974
|
@ -20,6 +20,7 @@ var (
|
|||
issue [-a <ASSIGNEE>] [-c <CREATOR>] [-@ <USER>] [-s <STATE>] [-f <FORMAT>] [-M <MILESTONE>] [-l <LABELS>] [-d <DATE>] [-o <SORT_KEY> [-^]] [-L <LIMIT>]
|
||||
issue create [-oc] [-m <MESSAGE>|-F <FILE>] [--edit] [-a <USERS>] [-M <MILESTONE>] [-l <LABELS>]
|
||||
issue labels [--color]
|
||||
issue show <NUMBER>
|
||||
`,
|
||||
Long: `Manage GitHub issues for the current project.
|
||||
|
||||
|
@ -153,6 +154,13 @@ With no arguments, show a list of open issues.
|
|||
Long: "Open an issue in the current project.",
|
||||
}
|
||||
|
||||
cmdShowIssue = &Command{
|
||||
Key: "show",
|
||||
Run: showIssue,
|
||||
Usage: "issue show <NUMBER>",
|
||||
Long: "Show an issue in the current project.",
|
||||
}
|
||||
|
||||
cmdLabel = &Command{
|
||||
Key: "labels",
|
||||
Run: listLabels,
|
||||
|
@ -213,6 +221,7 @@ func init() {
|
|||
|
||||
cmdLabel.Flag.BoolVarP(&flagLabelsColorize, "color", "", false, "COLORIZE")
|
||||
|
||||
cmdIssue.Use(cmdShowIssue)
|
||||
cmdIssue.Use(cmdCreateIssue)
|
||||
cmdIssue.Use(cmdLabel)
|
||||
CmdRunner.Use(cmdIssue)
|
||||
|
@ -371,6 +380,68 @@ func formatIssue(issue github.Issue, format string, colorize bool) string {
|
|||
return ui.Expand(format, placeholders, colorize)
|
||||
}
|
||||
|
||||
func showIssue(cmd *Command, args *Args) {
|
||||
issueNumber := cmd.Arg(0)
|
||||
if issueNumber == "" {
|
||||
utils.Check(fmt.Errorf(cmd.Synopsis()))
|
||||
}
|
||||
|
||||
localRepo, err := github.LocalRepo()
|
||||
utils.Check(err)
|
||||
|
||||
project, err := localRepo.MainProject()
|
||||
utils.Check(err)
|
||||
|
||||
gh := github.NewClient(project.Host)
|
||||
|
||||
var issue = &github.Issue{}
|
||||
issue, err = gh.FetchIssue(project, issueNumber)
|
||||
utils.Check(err)
|
||||
|
||||
var closed = ""
|
||||
if issue.State != "open" {
|
||||
closed = "[CLOSED] "
|
||||
}
|
||||
commentsList, err := gh.FetchComments(project, issueNumber)
|
||||
utils.Check(err)
|
||||
|
||||
var assignees []string
|
||||
var assigneesString = ""
|
||||
if len(issue.Assignees) > 0 {
|
||||
for _, user := range issue.Assignees {
|
||||
assignees = append(assignees, user.Login)
|
||||
}
|
||||
assigneesString = fmt.Sprintf("* assignees: %s\n\n", strings.Join(assignees, ", "))
|
||||
}
|
||||
|
||||
var comments []string
|
||||
var commentsString = ""
|
||||
if issue.Comments > 0 {
|
||||
for _, comment := range commentsList {
|
||||
comments = append(comments, fmt.Sprintf(
|
||||
"### comment by @%s on %s\n\n"+
|
||||
"%s\n", comment.User.Login, comment.CreatedAt.String(), comment.Body))
|
||||
}
|
||||
commentsString = fmt.Sprintf("\n## Comments:\n\n%s", strings.Join(comments, ""))
|
||||
|
||||
}
|
||||
|
||||
ui.Printf("# %s\n\n"+
|
||||
"* created by @%s on %s\n"+
|
||||
"%s"+
|
||||
"%s\n"+
|
||||
"%s",
|
||||
closed+issue.Title,
|
||||
issue.User.Login,
|
||||
issue.CreatedAt.String(),
|
||||
assigneesString,
|
||||
issue.Body,
|
||||
commentsString)
|
||||
|
||||
args.NoForward()
|
||||
return
|
||||
}
|
||||
|
||||
func createIssue(cmd *Command, args *Args) {
|
||||
localRepo, err := github.LocalRepo()
|
||||
utils.Check(err)
|
||||
|
|
|
@ -530,3 +530,84 @@ Feature: hub issue
|
|||
bug
|
||||
feature\n
|
||||
"""
|
||||
|
||||
|
||||
Scenario: Fetch single issue
|
||||
Given the GitHub API server:
|
||||
"""
|
||||
get('/repos/github/hub/issues/102') { json \
|
||||
:number => 102,
|
||||
:state => "open",
|
||||
:body => "I want this feature",
|
||||
:title => "Feature request for hub issue show",
|
||||
:created_at => "2017-04-14T16:00:49Z",
|
||||
:user => { :login => "royels" },
|
||||
:assignees => [{:login => "royels"}],
|
||||
:comments => 1
|
||||
}
|
||||
get('/repos/github/hub/issues/102/comments') {
|
||||
json [{
|
||||
:id => 1,
|
||||
:body => "I am from the future",
|
||||
:created_at => "2011-04-14T16:00:49Z",
|
||||
:user => { :login => "octocat" }}
|
||||
]
|
||||
}
|
||||
"""
|
||||
When I successfully run `hub issue show 102`
|
||||
Then the output should contain exactly:
|
||||
"""
|
||||
# Feature request for hub issue show
|
||||
|
||||
* created by @royels on 2017-04-14 16:00:49 +0000 UTC
|
||||
* assignees: royels
|
||||
|
||||
I want this feature
|
||||
|
||||
## Comments:
|
||||
|
||||
### comment by @octocat on 2011-04-14 16:00:49 +0000 UTC
|
||||
|
||||
I am from the future
|
||||
|
||||
"""
|
||||
|
||||
Scenario: Did not supply an issue number
|
||||
When I run `hub issue show`
|
||||
Then the exit status should be 1
|
||||
Then the output should contain exactly "Usage: hub issue show <NUMBER>\n"
|
||||
|
||||
|
||||
Scenario: Show error message if http code is not 200 for issues endpoint
|
||||
Given the GitHub API server:
|
||||
"""
|
||||
get('/repos/github/hub/issues/102') {
|
||||
status 500
|
||||
}
|
||||
"""
|
||||
When I run `hub issue show 102`
|
||||
Then the output should contain exactly:
|
||||
"""
|
||||
Error fetching issue: Internal Server Error (HTTP 500)\n
|
||||
"""
|
||||
|
||||
|
||||
Scenario: Show error message if http code is not 200 for comments endpoint
|
||||
Given the GitHub API server:
|
||||
"""
|
||||
get('/repos/github/hub/issues/102') { json \
|
||||
:number => 102,
|
||||
:body => "I want this feature",
|
||||
:title => "Feature request for hub issue show",
|
||||
:created_at => "2017-04-14T16:00:49Z",
|
||||
:user => { :login => "royels" }
|
||||
}
|
||||
get('/repos/github/hub/issues/102/comments') {
|
||||
status 404
|
||||
}
|
||||
"""
|
||||
When I run `hub issue show 102`
|
||||
Then the output should contain exactly:
|
||||
"""
|
||||
Error fetching comments for issue: Not Found (HTTP 404)\n
|
||||
"""
|
|
@ -525,6 +525,13 @@ func (client *Client) ForkRepository(project *Project, params map[string]interfa
|
|||
return
|
||||
}
|
||||
|
||||
type Comment struct {
|
||||
Id int `json:"id"`
|
||||
Body string `json:"body"`
|
||||
User *User `json:"user"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type Issue struct {
|
||||
Number int `json:"number"`
|
||||
State string `json:"state"`
|
||||
|
@ -550,6 +557,8 @@ type Issue struct {
|
|||
|
||||
ApiUrl string `json:"url"`
|
||||
HtmlUrl string `json:"html_url"`
|
||||
|
||||
ClosedBy *User `json:"closed_by"`
|
||||
}
|
||||
|
||||
type PullRequest Issue
|
||||
|
@ -649,6 +658,38 @@ func (client *Client) FetchIssues(project *Project, filterParams map[string]inte
|
|||
return
|
||||
}
|
||||
|
||||
func (client *Client) FetchIssue(project *Project, number string) (issue *Issue, err error) {
|
||||
api, err := client.simpleApi()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res, err := api.Get(fmt.Sprintf("repos/%s/%s/issues/%s", project.Owner, project.Name, number))
|
||||
if err = checkStatus(200, "fetching issue", res, err); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
issue = &Issue{}
|
||||
err = res.Unmarshal(issue)
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) FetchComments(project *Project, number string) (comments []Comment, err error) {
|
||||
api, err := client.simpleApi()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res, err := api.Get(fmt.Sprintf("repos/%s/%s/issues/%s/comments", project.Owner, project.Name, number))
|
||||
if err = checkStatus(200, "fetching comments for issue", res, err); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comments = []Comment{}
|
||||
err = res.Unmarshal(&comments)
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) CreateIssue(project *Project, params interface{}) (issue *Issue, err error) {
|
||||
api, err := client.simpleApi()
|
||||
if err != nil {
|
||||
|
|
Загрузка…
Ссылка в новой задаче