X Tutup
Skip to content

Commit c00fe73

Browse files
committed
Isolate issue commands
1 parent 20e3045 commit c00fe73

26 files changed

+2178
-1664
lines changed

command/issue.go

Lines changed: 0 additions & 694 deletions
This file was deleted.

command/issue_test.go

Lines changed: 0 additions & 962 deletions
This file was deleted.

command/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/cli/cli/internal/run"
2424
apiCmd "github.com/cli/cli/pkg/cmd/api"
2525
gistCreateCmd "github.com/cli/cli/pkg/cmd/gist/create"
26+
issueCmd "github.com/cli/cli/pkg/cmd/issue"
2627
prCmd "github.com/cli/cli/pkg/cmd/pr"
2728
repoCmd "github.com/cli/cli/pkg/cmd/repo"
2829
repoCloneCmd "github.com/cli/cli/pkg/cmd/repo/clone"
@@ -169,6 +170,7 @@ func init() {
169170
repoCmd.Cmd.AddCommand(creditsCmd.NewCmdRepoCredits(&repoResolvingCmdFactory, nil))
170171

171172
RootCmd.AddCommand(prCmd.NewCmdPR(&repoResolvingCmdFactory))
173+
RootCmd.AddCommand(issueCmd.NewCmdIssue(&repoResolvingCmdFactory))
172174
RootCmd.AddCommand(creditsCmd.NewCmdCredits(cmdFactory, nil))
173175
}
174176

pkg/cmd/issue/close/close.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package close
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
7+
"github.com/cli/cli/api"
8+
"github.com/cli/cli/internal/config"
9+
"github.com/cli/cli/internal/ghrepo"
10+
"github.com/cli/cli/pkg/cmd/issue/shared"
11+
"github.com/cli/cli/pkg/cmdutil"
12+
"github.com/cli/cli/pkg/iostreams"
13+
"github.com/cli/cli/utils"
14+
"github.com/spf13/cobra"
15+
)
16+
17+
type CloseOptions struct {
18+
HttpClient func() (*http.Client, error)
19+
Config func() (config.Config, error)
20+
IO *iostreams.IOStreams
21+
BaseRepo func() (ghrepo.Interface, error)
22+
23+
SelectorArg string
24+
}
25+
26+
func NewCmdClose(f *cmdutil.Factory, runF func(*CloseOptions) error) *cobra.Command {
27+
opts := &CloseOptions{
28+
IO: f.IOStreams,
29+
HttpClient: f.HttpClient,
30+
Config: f.Config,
31+
}
32+
33+
cmd := &cobra.Command{
34+
Use: "close {<number> | <url>}",
35+
Short: "Close issue",
36+
Args: cobra.ExactArgs(1),
37+
RunE: func(cmd *cobra.Command, args []string) error {
38+
// support `-R, --repo` override
39+
opts.BaseRepo = f.BaseRepo
40+
41+
if len(args) > 0 {
42+
opts.SelectorArg = args[0]
43+
}
44+
45+
if runF != nil {
46+
return runF(opts)
47+
}
48+
return closeRun(opts)
49+
},
50+
}
51+
52+
return cmd
53+
}
54+
55+
func closeRun(opts *CloseOptions) error {
56+
httpClient, err := opts.HttpClient()
57+
if err != nil {
58+
return err
59+
}
60+
apiClient := api.NewClientFromHTTP(httpClient)
61+
62+
issue, baseRepo, err := shared.IssueFromArg(apiClient, opts.BaseRepo, opts.SelectorArg)
63+
if err != nil {
64+
return err
65+
}
66+
67+
if issue.Closed {
68+
fmt.Fprintf(opts.IO.ErrOut, "%s Issue #%d (%s) is already closed\n", utils.Yellow("!"), issue.Number, issue.Title)
69+
return nil
70+
}
71+
72+
err = api.IssueClose(apiClient, baseRepo, *issue)
73+
if err != nil {
74+
return err
75+
}
76+
77+
fmt.Fprintf(opts.IO.ErrOut, "%s Closed issue #%d (%s)\n", utils.Red("✔"), issue.Number, issue.Title)
78+
79+
return nil
80+
}

pkg/cmd/issue/close/close_test.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package close
2+
3+
import (
4+
"bytes"
5+
"io/ioutil"
6+
"net/http"
7+
"regexp"
8+
"testing"
9+
10+
"github.com/cli/cli/internal/config"
11+
"github.com/cli/cli/internal/ghrepo"
12+
"github.com/cli/cli/pkg/cmdutil"
13+
"github.com/cli/cli/pkg/httpmock"
14+
"github.com/cli/cli/pkg/iostreams"
15+
"github.com/cli/cli/test"
16+
"github.com/google/shlex"
17+
)
18+
19+
func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, error) {
20+
io, _, stdout, stderr := iostreams.Test()
21+
io.SetStdoutTTY(isTTY)
22+
io.SetStdinTTY(isTTY)
23+
io.SetStderrTTY(isTTY)
24+
25+
factory := &cmdutil.Factory{
26+
IOStreams: io,
27+
HttpClient: func() (*http.Client, error) {
28+
return &http.Client{Transport: rt}, nil
29+
},
30+
Config: func() (config.Config, error) {
31+
return config.NewBlankConfig(), nil
32+
},
33+
BaseRepo: func() (ghrepo.Interface, error) {
34+
return ghrepo.New("OWNER", "REPO"), nil
35+
},
36+
}
37+
38+
cmd := NewCmdClose(factory, nil)
39+
40+
argv, err := shlex.Split(cli)
41+
if err != nil {
42+
return nil, err
43+
}
44+
cmd.SetArgs(argv)
45+
46+
cmd.SetIn(&bytes.Buffer{})
47+
cmd.SetOut(ioutil.Discard)
48+
cmd.SetErr(ioutil.Discard)
49+
50+
_, err = cmd.ExecuteC()
51+
return &test.CmdOut{
52+
OutBuf: stdout,
53+
ErrBuf: stderr,
54+
}, err
55+
}
56+
57+
func TestIssueClose(t *testing.T) {
58+
http := &httpmock.Registry{}
59+
defer http.Verify(t)
60+
61+
http.StubResponse(200, bytes.NewBufferString(`
62+
{ "data": { "repository": {
63+
"hasIssuesEnabled": true,
64+
"issue": { "number": 13, "title": "The title of the issue"}
65+
} } }
66+
`))
67+
68+
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
69+
70+
output, err := runCommand(http, true, "13")
71+
if err != nil {
72+
t.Fatalf("error running command `issue close`: %v", err)
73+
}
74+
75+
r := regexp.MustCompile(`Closed issue #13 \(The title of the issue\)`)
76+
77+
if !r.MatchString(output.Stderr()) {
78+
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
79+
}
80+
}
81+
82+
func TestIssueClose_alreadyClosed(t *testing.T) {
83+
http := &httpmock.Registry{}
84+
defer http.Verify(t)
85+
86+
http.StubResponse(200, bytes.NewBufferString(`
87+
{ "data": { "repository": {
88+
"hasIssuesEnabled": true,
89+
"issue": { "number": 13, "title": "The title of the issue", "closed": true}
90+
} } }
91+
`))
92+
93+
output, err := runCommand(http, true, "13")
94+
if err != nil {
95+
t.Fatalf("error running command `issue close`: %v", err)
96+
}
97+
98+
r := regexp.MustCompile(`Issue #13 \(The title of the issue\) is already closed`)
99+
100+
if !r.MatchString(output.Stderr()) {
101+
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
102+
}
103+
}
104+
105+
func TestIssueClose_issuesDisabled(t *testing.T) {
106+
http := &httpmock.Registry{}
107+
defer http.Verify(t)
108+
109+
http.StubResponse(200, bytes.NewBufferString(`
110+
{ "data": { "repository": {
111+
"hasIssuesEnabled": false
112+
} } }
113+
`))
114+
115+
_, err := runCommand(http, true, "13")
116+
if err == nil || err.Error() != "the 'OWNER/REPO' repository has disabled issues" {
117+
t.Fatalf("got error: %v", err)
118+
}
119+
}

0 commit comments

Comments
 (0)
X Tutup