Merge remote-tracking branch 'origin/master' into add-pr-show

This commit is contained in:
Corey Johnson 2019-10-16 12:48:12 -07:00
commit 9fe04dc033
19 changed files with 293 additions and 12 deletions

View file

@ -21,7 +21,7 @@ type graphQLResponse struct {
}
/*
graphQL usage
GraphQL: Declared as an external variable so it can be mocked in tests
type repoResponse struct {
Repository struct {
@ -45,7 +45,7 @@ if err != nil {
fmt.Printf("%+v\n", resp)
*/
func graphQL(query string, variables map[string]string, data interface{}) error {
var GraphQL = func(query string, variables map[string]string, data interface{}) error {
url := "https://api.github.com/graphql"
reqBody, err := json.Marshal(map[string]interface{}{"query": query, "variables": variables})
if err != nil {

View file

@ -98,7 +98,7 @@ func PullRequests() (PullRequestsPayload, error) {
}
var resp response
err := graphQL(query, variables, &resp)
err := GraphQL(query, variables, &resp)
if err != nil {
return PullRequestsPayload{}, err
}
@ -133,7 +133,6 @@ func project() github.Project {
if error != nil {
panic(error)
}
for _, remote := range remotes {
if project, error := remote.Project(); error == nil {
return *project

View file

@ -12,7 +12,6 @@ import (
"github.com/github/gh-cli/git"
"github.com/github/gh-cli/github"
"github.com/github/gh-cli/utils"
"github.com/logrusorgru/aurora"
"github.com/spf13/cobra"
)
@ -53,7 +52,7 @@ func prList(cmd *cobra.Command, args []string) error {
if prPayload.CurrentPR != nil {
printPrs(*prPayload.CurrentPR)
} else {
message := fmt.Sprintf(" There is no pull request associated with %s", aurora.Cyan("["+currentBranch()+"]"))
message := fmt.Sprintf(" There is no pull request associated with %s", utils.Cyan("["+currentBranch()+"]"))
printMessage(message)
}
fmt.Println()
@ -102,16 +101,16 @@ func prView(cmd *cobra.Command, args []string) error {
func printPrs(prs ...api.PullRequest) {
for _, pr := range prs {
fmt.Printf(" #%d %s [%s]\n", pr.Number, truncateTitle(pr.Title), aurora.Cyan(pr.HeadRefName))
fmt.Printf(" #%d %s %s\n", pr.Number, truncateTitle(pr.Title), utils.Cyan("["+pr.HeadRefName+"]"))
}
}
func printHeader(s string) {
fmt.Println(aurora.Bold(s))
fmt.Println(utils.Bold(s))
}
func printMessage(s string) {
fmt.Println(aurora.Gray(8, s))
fmt.Println(utils.Gray(s))
}
func truncateTitle(title string) string {

34
command/pr_test.go Normal file
View file

@ -0,0 +1,34 @@
package command
import (
"regexp"
"testing"
"github.com/github/gh-cli/test"
)
func TestPRList(t *testing.T) {
teardown := test.MockGraphQLResponse("test/fixtures/pr.json")
defer teardown()
gitRepo := test.UseTempGitRepo()
defer gitRepo.TearDown()
output, err := test.RunCommand(RootCmd, "pr list")
if err != nil {
t.Errorf("error running command `pr list`: %v", err)
}
expectedPrs := []*regexp.Regexp{
regexp.MustCompile(`#8.*\[strawberries\]`),
regexp.MustCompile(`#9.*\[apples\]`),
regexp.MustCompile(`#10.*\[blueberries\]`),
regexp.MustCompile(`#11.*\[figs\]`),
}
for _, r := range expectedPrs {
if !r.MatchString(output) {
t.Errorf("output did not match regexp /%s/", r)
}
}
}

2
go.mod
View file

@ -4,8 +4,8 @@ go 1.13
require (
github.com/BurntSushi/toml v0.3.1
github.com/gookit/color v1.2.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/logrusorgru/aurora v0.0.0-20190803045625-94edacc10f9b
github.com/mattn/go-colorable v0.1.2
github.com/mattn/go-isatty v0.0.9
github.com/mitchellh/go-homedir v1.1.0

10
go.sum
View file

@ -5,15 +5,17 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gookit/color v1.2.0 h1:lHA77Kuyi5JpBnA9ESvwkY+nanLjRZ0mHbWQXRYk2Lk=
github.com/gookit/color v1.2.0/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/logrusorgru/aurora v0.0.0-20190803045625-94edacc10f9b h1:PMbSa9CgaiQR9NLlUTwKi+7aeLl3GG5JX5ERJxfQ3IE=
github.com/logrusorgru/aurora v0.0.0-20190803045625-94edacc10f9b/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@ -24,6 +26,7 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@ -34,7 +37,10 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

50
test/fixtures/pr.json vendored Normal file
View file

@ -0,0 +1,50 @@
{
"repository": {
"pullRequests": {
"edges": [
{
"node": {
"number": 10,
"title": "Blueberries are a good fruit",
"url": "https://github.com/github/gh-cli/pull/10",
"headRefName": "[blueberries]"
}
}
]
}
},
"viewerCreated": {
"edges": [
{
"node": {
"number": 8,
"title": "Strawberries are not actually berries",
"url": "https://github.com/github/gh-cli/pull/8",
"headRefName": "[strawberries]"
}
}
],
"pageInfo": { "hasNextPage": false }
},
"reviewRequested": {
"edges": [
{
"node": {
"number": 9,
"title": "Apples are tasty",
"url": "https://github.com/github/gh-cli/pull/9",
"headRefName": "[apples]"
}
},
{
"node": {
"number": 11,
"title": "Figs are my favorite",
"url": "https://github.com/github/gh-cli/pull/1",
"headRefName": "[figs]"
}
}
],
"pageInfo": { "hasNextPage": false }
}
}

1
test/fixtures/test.git/HEAD vendored Normal file
View file

@ -0,0 +1 @@
ref: refs/heads/master

6
test/fixtures/test.git/config vendored Normal file
View file

@ -0,0 +1,6 @@
[core]
repositoryformatversion = 0
filemode = true
bare = true
ignorecase = true
precomposeunicode = false

6
test/fixtures/test.git/info/exclude vendored Normal file
View file

@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

View file

@ -0,0 +1,3 @@
x<01><>M
Â0F]çseb~œ€ˆnÝx™¦cMi¨)^ß 7pó>xðñbÉ9UÐä7ub{ŽÖbgÙ´íă#h8<68>÷<01>âµ>Ë×4o™áöÅ
Çñ'ÊyÈœ¦],ùÚ„½Fkœ†-¢j¶U«üûW—¾‡*¯z¤IÔ)”;â

View file

@ -0,0 +1,3 @@
x<01><>K
1D]η}¥3ι$qεBΟ<>dq&#^ίρs7UPΕ«XΖqhΠ/ZM Άw*<2A>cbc±G”3ΩΛ½ΦYηΠI<CEA0>βζk<CEB6> g
6-U<>s4iΦ6³1χFΆμ#Y,ό£<CF8C>K…ύ0<CF8D><30>iγG°Ύ|ƒ²=<3D>~Έ®b7 •λ$b KdD1§3eK<65>φΕn¨χο™Z<>σΥ<CF83>{Nm

View file

@ -0,0 +1 @@
9b5a719a3d76ac9dc2fa635d9b1f34fd73994c06

130
test/helpers.go Normal file
View file

@ -0,0 +1,130 @@
package test
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/github/gh-cli/api"
"github.com/github/gh-cli/github"
"github.com/spf13/cobra"
)
type TempGitRepo struct {
Remote string
TearDown func()
}
func UseTempGitRepo() *TempGitRepo {
github.CreateTestConfigs("mario", "i-love-peach")
pwd, _ := os.Getwd()
oldEnv := make(map[string]string)
overrideEnv := func(name, value string) {
oldEnv[name] = os.Getenv(name)
os.Setenv(name, value)
}
remotePath := filepath.Join(pwd, "..", "test", "fixtures", "test.git")
home, err := ioutil.TempDir("", "test-repo")
if err != nil {
panic(err)
}
overrideEnv("HOME", home)
overrideEnv("XDG_CONFIG_HOME", "")
overrideEnv("XDG_CONFIG_DIRS", "")
targetPath := filepath.Join(home, "test.git")
cmd := exec.Command("git", "clone", remotePath, targetPath)
if output, err := cmd.Output(); err != nil {
panic(fmt.Errorf("error running %s\n%s\n%s", cmd, err, output))
}
if err = os.Chdir(targetPath); err != nil {
panic(err)
}
// Our libs expect the origin to be a github url
cmd = exec.Command("git", "remote", "set-url", "origin", "https://github.com/github/FAKE-GITHUB-REPO-NAME")
if output, err := cmd.Output(); err != nil {
panic(fmt.Errorf("error running %s\n%s\n%s", cmd, err, output))
}
tearDown := func() {
if err := os.Chdir(pwd); err != nil {
panic(err)
}
for name, value := range oldEnv {
os.Setenv(name, value)
}
if err = os.RemoveAll(home); err != nil {
panic(err)
}
}
return &TempGitRepo{Remote: remotePath, TearDown: tearDown}
}
func MockGraphQLResponse(fixturePath string) (teardown func()) {
pwd, _ := os.Getwd()
fixturePath = filepath.Join(pwd, "..", fixturePath)
originalGraphQL := api.GraphQL
api.GraphQL = func(query string, variables map[string]string, v interface{}) error {
contents, err := ioutil.ReadFile(fixturePath)
if err != nil {
return err
}
json.Unmarshal(contents, &v)
if err != nil {
return err
}
return nil
}
return func() {
api.GraphQL = originalGraphQL
}
}
func RunCommand(root *cobra.Command, s string) (string, error) {
var err error
output := captureOutput(func() {
root.SetArgs(strings.Split(s, " "))
_, err = root.ExecuteC()
})
if err != nil {
return "", err
}
return output, nil
}
func captureOutput(f func()) string {
originalStdout := os.Stdout
defer func() {
os.Stdout = originalStdout
}()
r, w, err := os.Pipe()
if err != nil {
panic("failed to pipe stdout")
}
os.Stdout = w
f()
w.Close()
out, err := ioutil.ReadAll(r)
if err != nil {
panic("failed to read captured input from stdout")
}
return string(out)
}

43
utils/color.go Normal file
View file

@ -0,0 +1,43 @@
package utils
import "github.com/gookit/color"
func Black(a ...interface{}) string {
return color.Black.Render(a...)
}
func White(a ...interface{}) string {
return color.White.Render(a...)
}
func Gray(a ...interface{}) string {
return color.Gray.Render(a...)
}
func Red(a ...interface{}) string {
return color.Red.Render(a...)
}
func Green(a ...interface{}) string {
return color.Green.Render(a...)
}
func Yellow(a ...interface{}) string {
return color.Yellow.Render(a...)
}
func Blue(a ...interface{}) string {
return color.Blue.Render(a...)
}
func Magenta(a ...interface{}) string {
return color.Magenta.Render(a...)
}
func Cyan(a ...interface{}) string {
return color.Cyan.Render(a...)
}
func Bold(a ...interface{}) string {
return color.Bold.Render(a...)
}