Merge remote-tracking branch 'origin/master' into ghrepo-interface

This commit is contained in:
Mislav Marohnić 2020-01-23 16:36:22 +01:00
commit c5960f0906
9 changed files with 131 additions and 20 deletions

View file

@ -23,4 +23,4 @@ jobs:
- name: Build
run: |
go test ./...
go build -v .
go build -v ./cmd/gh

View file

@ -8,6 +8,7 @@ before:
- go mod tidy
builds:
- binary: bin/gh
main: ./cmd/gh
ldflags:
- -s -w -X github.com/github/gh-cli/command.Version={{.Version}} -X github.com/github/gh-cli/command.BuildDate={{time "2006-01-02"}}
- -X github.com/github/gh-cli/context.oauthClientID={{.Env.GH_OAUTH_CLIENT_ID}}

View file

@ -10,7 +10,7 @@ ifdef GH_OAUTH_CLIENT_SECRET
endif
bin/gh: $(BUILD_FILES)
@go build -ldflags "$(LDFLAGS)" -o "$@"
@go build -ldflags "$(LDFLAGS)" -o "$@" ./cmd/gh
test:
go test ./...

View file

@ -1,7 +1,10 @@
package main
import (
"errors"
"fmt"
"io"
"net"
"os"
"path"
"strings"
@ -12,6 +15,7 @@ import (
"github.com/github/gh-cli/utils"
"github.com/mattn/go-isatty"
"github.com/mgutz/ansi"
"github.com/spf13/cobra"
)
var updaterEnabled = ""
@ -24,12 +28,10 @@ func main() {
updateMessageChan <- rel
}()
hasDebug := os.Getenv("DEBUG") != ""
if cmd, err := command.RootCmd.ExecuteC(); err != nil {
fmt.Fprintln(os.Stderr, err)
_, isFlagError := err.(command.FlagError)
if isFlagError || strings.HasPrefix(err.Error(), "unknown command ") {
fmt.Fprintln(os.Stderr, cmd.UsageString())
}
printError(os.Stderr, err, cmd, hasDebug)
os.Exit(1)
}
@ -46,6 +48,28 @@ func main() {
}
}
func printError(out io.Writer, err error, cmd *cobra.Command, debug bool) {
var dnsError *net.DNSError
if errors.As(err, &dnsError) {
fmt.Fprintf(out, "error connecting to %s\n", dnsError.Name)
if debug {
fmt.Fprintln(out, dnsError)
}
fmt.Fprintln(out, "check your internet connection or githubstatus.com")
return
}
fmt.Fprintln(out, err)
var flagError *command.FlagError
if errors.As(err, &flagError) || strings.HasPrefix(err.Error(), "unknown command ") {
if !strings.HasSuffix(err.Error(), "\n") {
fmt.Fprintln(out)
}
fmt.Fprintln(out, cmd.UsageString())
}
}
func shouldCheckForUpdate() bool {
errFd := os.Stderr.Fd()
return updaterEnabled != "" && (isatty.IsTerminal(errFd) || isatty.IsCygwinTerminal(errFd))

78
cmd/gh/main_test.go Normal file
View file

@ -0,0 +1,78 @@
package main
import (
"bytes"
"errors"
"fmt"
"net"
"testing"
"github.com/github/gh-cli/command"
"github.com/spf13/cobra"
)
func Test_printError(t *testing.T) {
cmd := &cobra.Command{}
type args struct {
err error
cmd *cobra.Command
debug bool
}
tests := []struct {
name string
args args
wantOut string
}{
{
name: "generic error",
args: args{
err: errors.New("the app exploded"),
cmd: nil,
debug: false,
},
wantOut: "the app exploded\n",
},
{
name: "DNS error",
args: args{
err: fmt.Errorf("DNS oopsie: %w", &net.DNSError{
Name: "api.github.com",
}),
cmd: nil,
debug: false,
},
wantOut: `error connecting to api.github.com
check your internet connection or githubstatus.com
`,
},
{
name: "Cobra flag error",
args: args{
err: &command.FlagError{Err: errors.New("unknown flag --foo")},
cmd: cmd,
debug: false,
},
wantOut: "unknown flag --foo\n\nUsage:\n\n",
},
{
name: "unknown Cobra command error",
args: args{
err: errors.New("unknown command foo"),
cmd: cmd,
debug: false,
},
wantOut: "unknown command foo\n\nUsage:\n\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out := &bytes.Buffer{}
printError(out, tt.args.err, tt.args.cmd, tt.args.debug)
if gotOut := out.String(); gotOut != tt.wantOut {
t.Errorf("printError() = %q, want %q", gotOut, tt.wantOut)
}
})
}
}

View file

@ -47,7 +47,7 @@ var issueCmd = &cobra.Command{
An issue can be supplied as argument in any of the following formats:
- by number, e.g. "123"; or
- by URL, e.g. "https://github.com/<owner>/<repo>/issues/123".`,
- by URL, e.g. "https://github.com/OWNER/REPO/issues/123".`,
}
var issueCreateCmd = &cobra.Command{
Use: "create",
@ -68,7 +68,7 @@ var issueViewCmd = &cobra.Command{
Use: "view {<number> | <url> | <branch>}",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("requires an issue number as an argument")
return FlagError{errors.New("issue required as argument")}
}
return nil
},

View file

@ -43,8 +43,8 @@ var prCmd = &cobra.Command{
A pull request can be supplied as argument in any of the following formats:
- by number, e.g. "123";
- by URL, e.g. "https://github.com/<owner>/<repo>/pull/123"; or
- by the name of its head branch, e.g. "patch-1" or "<owner>:patch-1".`,
- by URL, e.g. "https://github.com/OWNER/REPO/pull/123"; or
- by the name of its head branch, e.g. "patch-1" or "OWNER:patch-1".`,
}
var prCheckoutCmd = &cobra.Command{
Use: "checkout {<number> | <url> | <branch>}",
@ -68,9 +68,13 @@ var prStatusCmd = &cobra.Command{
RunE: prStatus,
}
var prViewCmd = &cobra.Command{
Use: "view {<number> | <url> | <branch>}",
Use: "view [{<number> | <url> | <branch>}]",
Short: "View a pull request in the browser",
RunE: prView,
Long: `View a pull request specified by the argument in the browser.
Without an argument, the pull request that belongs to the current
branch is opened.`,
RunE: prView,
}
func prStatus(cmd *cobra.Command, args []string) error {
@ -286,10 +290,6 @@ func prView(cmd *cobra.Command, args []string) error {
} else {
pr, err = api.PullRequestForBranch(apiClient, baseRepo, branchWithOwner)
if err != nil {
var notFoundErr *api.NotFoundError
if errors.As(err, &notFoundErr) {
return fmt.Errorf("%s. To open a specific pull request use the pull request's number as an argument", err)
}
return err
}

View file

@ -359,7 +359,7 @@ func TestPRView_noResultsForBranch(t *testing.T) {
defer restoreCmd()
_, err := RunCommand(prViewCmd, "pr view")
if err == nil || err.Error() != `no open pull requests found for branch "blueberries". To open a specific pull request use the pull request's number as an argument` {
if err == nil || err.Error() != `no open pull requests found for branch "blueberries"` {
t.Errorf("error running command `pr view`: %v", err)
}

View file

@ -35,13 +35,21 @@ func init() {
// RootCmd.PersistentFlags().BoolP("verbose", "V", false, "enable verbose output")
RootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
return FlagError{err}
return &FlagError{Err: err}
})
}
// FlagError is the kind of error raised in flag processing
type FlagError struct {
error
Err error
}
func (fe FlagError) Error() string {
return fe.Err.Error()
}
func (fe FlagError) Unwrap() error {
return fe.Err
}
// RootCmd is the entry point of command-line execution