Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for localhost #51

Merged
merged 1 commit into from Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 13 additions & 7 deletions internal/api/gql_client.go
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io"
"net/http"
"strings"

"github.com/cli/go-gh/pkg/api"

Expand All @@ -23,15 +24,9 @@ type gqlClient struct {
func NewGQLClient(host string, opts *api.ClientOptions) api.GQLClient {
httpClient := NewHTTPClient(opts)

if isEnterprise(host) {
host = fmt.Sprintf("https://%s/api/graphql", host)
} else {
host = "https://api.github.com/graphql"
}

return gqlClient{
client: graphql.NewClient(host, &httpClient),
host: host,
host: gqlEndpoint(host),
httpClient: &httpClient,
}
}
Expand Down Expand Up @@ -114,3 +109,14 @@ type gqlResponse struct {
Data interface{}
Errors []api.GQLErrorItem
}

func gqlEndpoint(host string) string {
host = normalizeHostname(host)
if isEnterprise(host) {
return fmt.Sprintf("https://%s/api/graphql", host)
}
if strings.EqualFold(host, localhost) {
return fmt.Sprintf("http://api.%s/graphql", host)
}
return fmt.Sprintf("https://api.%s/graphql", host)
}
31 changes: 31 additions & 0 deletions internal/api/gql_client_test.go
Expand Up @@ -167,3 +167,34 @@ func TestGQLClientDoWithContext(t *testing.T) {
})
}
}

func TestGQLEndpoint(t *testing.T) {
tests := []struct {
name string
host string
wantEndpoint string
}{
{
name: "github",
host: "github.com",
wantEndpoint: "https://api.github.com/graphql",
},
{
name: "localhost",
host: "github.localhost",
wantEndpoint: "http://api.github.localhost/graphql",
},
{
name: "enterprise",
host: "enterprise.com",
wantEndpoint: "https://enterprise.com/api/graphql",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
endpoint := gqlEndpoint(tt.host)
assert.Equal(t, tt.wantEndpoint, endpoint)
})
}
}
16 changes: 14 additions & 2 deletions internal/api/http.go
Expand Up @@ -19,8 +19,9 @@ const (
accept = "Accept"
authorization = "Authorization"
contentType = "Content-Type"
defaultHostname = "github.com"
github = "github.com"
jsonContentType = "application/json; charset=utf-8"
localhost = "github.localhost"
modulePath = "github.com/cli/go-gh"
timeZone = "Time-Zone"
userAgent = "User-Agent"
Expand Down Expand Up @@ -127,7 +128,18 @@ func isSameDomain(requestHost, domain string) bool {
}

func isEnterprise(host string) bool {
return host != defaultHostname
return host != github && host != localhost
}

func normalizeHostname(hostname string) string {
hostname = strings.ToLower(hostname)
if strings.HasSuffix(hostname, "."+github) {
return github
}
if strings.HasSuffix(hostname, "."+localhost) {
return localhost
}
return hostname
}

type headerRoundTripper struct {
Expand Down
67 changes: 67 additions & 0 deletions internal/api/http_test.go
Expand Up @@ -121,6 +121,73 @@ func TestNewHTTPClient(t *testing.T) {
}
}

func TestIsEnterprise(t *testing.T) {
tests := []struct {
name string
host string
wantOut bool
}{
{
name: "github",
host: "github.com",
wantOut: false,
},
{
name: "localhost",
host: "github.localhost",
wantOut: false,
},
{
name: "enterprise",
host: "mygithub.com",
wantOut: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out := isEnterprise(tt.host)
assert.Equal(t, tt.wantOut, out)
})
}
}

func TestNormalizeHostname(t *testing.T) {
tests := []struct {
name string
host string
wantHost string
}{
{
name: "github domain",
host: "test.github.com",
wantHost: "github.com",
},
{
name: "capitalized",
host: "GitHub.com",
wantHost: "github.com",
},
{
name: "localhost domain",
host: "test.github.localhost",
wantHost: "github.localhost",
},
{
name: "enterprise domain",
host: "mygithub.com",
wantHost: "mygithub.com",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
normalized := normalizeHostname(tt.host)
assert.Equal(t, tt.wantHost, normalized)
})
}
}

type tripper struct {
roundTrip func(*http.Request) (*http.Response, error)
}
Expand Down
6 changes: 5 additions & 1 deletion internal/api/rest_client.go
Expand Up @@ -119,8 +119,12 @@ func restURL(hostname string, pathOrURL string) string {
}

func restPrefix(hostname string) string {
hostname = normalizeHostname(hostname)
if isEnterprise(hostname) {
return fmt.Sprintf("https://%s/api/v3/", hostname)
}
return "https://api.github.com/"
if strings.EqualFold(hostname, localhost) {
return fmt.Sprintf("http://api.%s/", hostname)
}
return fmt.Sprintf("https://api.%s/", hostname)
}
31 changes: 31 additions & 0 deletions internal/api/rest_client_test.go
Expand Up @@ -390,6 +390,37 @@ func TestRESTClientRequestWithContext(t *testing.T) {
}
}

func TestRestPrefix(t *testing.T) {
tests := []struct {
name string
host string
wantEndpoint string
}{
{
name: "github",
host: "github.com",
wantEndpoint: "https://api.github.com/",
},
{
name: "localhost",
host: "github.localhost",
wantEndpoint: "http://api.github.localhost/",
},
{
name: "enterprise",
host: "enterprise.com",
wantEndpoint: "https://enterprise.com/api/v3/",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
endpoint := restPrefix(tt.host)
assert.Equal(t, tt.wantEndpoint, endpoint)
})
}
}

func printPendingMocks(mocks []gock.Mock) string {
paths := []string{}
for _, mock := range mocks {
Expand Down
6 changes: 5 additions & 1 deletion pkg/auth/auth.go
Expand Up @@ -21,6 +21,7 @@ const (
githubEnterpriseToken = "GITHUB_ENTERPRISE_TOKEN"
githubToken = "GITHUB_TOKEN"
hostsKey = "hosts"
localhost = "github.localhost"
oauthToken = "oauth_token"
)

Expand Down Expand Up @@ -114,13 +115,16 @@ func defaultHost(cfg *config.Config) (string, string) {
}

func isEnterprise(host string) bool {
return host != github
return host != github && host != localhost
}

func normalizeHostname(host string) string {
hostname := strings.ToLower(host)
if strings.HasSuffix(hostname, "."+github) {
return github
}
if strings.HasSuffix(hostname, "."+localhost) {
return localhost
}
return hostname
}
67 changes: 67 additions & 0 deletions pkg/auth/auth_test.go
Expand Up @@ -223,6 +223,73 @@ func TestKnownHosts(t *testing.T) {
}
}

func TestIsEnterprise(t *testing.T) {
tests := []struct {
name string
host string
wantOut bool
}{
{
name: "github",
host: "github.com",
wantOut: false,
},
{
name: "localhost",
host: "github.localhost",
wantOut: false,
},
{
name: "enterprise",
host: "mygithub.com",
wantOut: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out := isEnterprise(tt.host)
assert.Equal(t, tt.wantOut, out)
})
}
}

func TestNormalizeHostname(t *testing.T) {
tests := []struct {
name string
host string
wantHost string
}{
{
name: "github domain",
host: "test.github.com",
wantHost: "github.com",
},
{
name: "capitalized",
host: "GitHub.com",
wantHost: "github.com",
},
{
name: "localhost domain",
host: "test.github.localhost",
wantHost: "github.localhost",
},
{
name: "enterprise domain",
host: "mygithub.com",
wantHost: "mygithub.com",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
normalized := normalizeHostname(tt.host)
assert.Equal(t, tt.wantHost, normalized)
})
}
}

func testNoHostsConfig() *config.Config {
var data = ``
return config.ReadFromString(data)
Expand Down