diff --git a/pkg/cmd/factory/http.go b/pkg/cmd/factory/http.go index 2e7619540..23534a0d3 100644 --- a/pkg/cmd/factory/http.go +++ b/pkg/cmd/factory/http.go @@ -8,7 +8,6 @@ import ( "time" "github.com/cli/cli/api" - "github.com/cli/cli/internal/config" "github.com/cli/cli/internal/ghinstance" "github.com/cli/cli/pkg/iostreams" ) @@ -53,8 +52,12 @@ var timezoneNames = map[int]string{ 50400: "Pacific/Kiritimati", } +type configGetter interface { + Get(string, string) (string, error) +} + // generic authenticated HTTP client for commands -func NewHTTPClient(io *iostreams.IOStreams, cfg config.Config, appVersion string, setAccept bool) *http.Client { +func NewHTTPClient(io *iostreams.IOStreams, cfg configGetter, appVersion string, setAccept bool) *http.Client { var opts []api.ClientOption if verbose := os.Getenv("DEBUG"); verbose != "" { logTraffic := strings.Contains(verbose, "api") @@ -64,7 +67,7 @@ func NewHTTPClient(io *iostreams.IOStreams, cfg config.Config, appVersion string opts = append(opts, api.AddHeader("User-Agent", fmt.Sprintf("GitHub CLI %s", appVersion)), api.AddHeaderFunc("Authorization", func(req *http.Request) (string, error) { - hostname := ghinstance.NormalizeHostname(req.URL.Hostname()) + hostname := ghinstance.NormalizeHostname(getHost(req)) if token, err := cfg.Get(hostname, "oauth_token"); err == nil && token != "" { return fmt.Sprintf("token %s", token), nil } @@ -85,13 +88,10 @@ func NewHTTPClient(io *iostreams.IOStreams, cfg config.Config, appVersion string if setAccept { opts = append(opts, api.AddHeaderFunc("Accept", func(req *http.Request) (string, error) { - // antiope-preview: Checks - accept := "application/vnd.github.antiope-preview+json" - // introduced for #2952: pr branch up to date status - accept += ", application/vnd.github.merge-info-preview+json" - if ghinstance.IsEnterprise(req.URL.Hostname()) { - // shadow-cat-preview: Draft pull requests - accept += ", application/vnd.github.shadow-cat-preview" + accept := "application/vnd.github.merge-info-preview+json" // PullRequest.mergeStateStatus + if ghinstance.IsEnterprise(getHost(req)) { + accept += ", application/vnd.github.antiope-preview" // Commit.statusCheckRollup + accept += ", application/vnd.github.shadow-cat-preview" // PullRequest.isDraft } return accept, nil }), @@ -100,3 +100,10 @@ func NewHTTPClient(io *iostreams.IOStreams, cfg config.Config, appVersion string return api.NewHTTPClient(opts...) } + +func getHost(r *http.Request) string { + if r.Host != "" { + return r.Host + } + return r.URL.Hostname() +} diff --git a/pkg/cmd/factory/http_test.go b/pkg/cmd/factory/http_test.go new file mode 100644 index 000000000..6172d846c --- /dev/null +++ b/pkg/cmd/factory/http_test.go @@ -0,0 +1,174 @@ +package factory + +import ( + "fmt" + "net/http" + "net/http/httptest" + "os" + "regexp" + "testing" + + "github.com/MakeNowJust/heredoc" + "github.com/cli/cli/pkg/iostreams" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewHTTPClient(t *testing.T) { + type args struct { + config configGetter + appVersion string + setAccept bool + } + tests := []struct { + name string + args args + envDebug string + host string + wantHeader map[string]string + wantStderr string + }{ + { + name: "github.com with Accept header", + args: args{ + config: tinyConfig{"github.com:oauth_token": "MYTOKEN"}, + appVersion: "v1.2.3", + setAccept: true, + }, + host: "github.com", + wantHeader: map[string]string{ + "authorization": "token MYTOKEN", + "user-agent": "GitHub CLI v1.2.3", + "accept": "application/vnd.github.merge-info-preview+json", + }, + wantStderr: "", + }, + { + name: "github.com no Accept header", + args: args{ + config: tinyConfig{"github.com:oauth_token": "MYTOKEN"}, + appVersion: "v1.2.3", + setAccept: false, + }, + host: "github.com", + wantHeader: map[string]string{ + "authorization": "token MYTOKEN", + "user-agent": "GitHub CLI v1.2.3", + "accept": "", + }, + wantStderr: "", + }, + { + name: "github.com no authentication token", + args: args{ + config: tinyConfig{"example.com:oauth_token": "MYTOKEN"}, + appVersion: "v1.2.3", + setAccept: true, + }, + host: "github.com", + wantHeader: map[string]string{ + "authorization": "", + "user-agent": "GitHub CLI v1.2.3", + "accept": "application/vnd.github.merge-info-preview+json", + }, + wantStderr: "", + }, + { + name: "github.com in verbose mode", + args: args{ + config: tinyConfig{"github.com:oauth_token": "MYTOKEN"}, + appVersion: "v1.2.3", + setAccept: true, + }, + host: "github.com", + envDebug: "api", + wantHeader: map[string]string{ + "authorization": "token MYTOKEN", + "user-agent": "GitHub CLI v1.2.3", + "accept": "application/vnd.github.merge-info-preview+json", + }, + wantStderr: heredoc.Doc(` + * Request at