Add tenancy support (#7636)
This commit is contained in:
parent
5a0f892d4a
commit
d21c11d774
4 changed files with 186 additions and 10 deletions
|
|
@ -6,37 +6,56 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// DefaultHostname is the domain name of the default GitHub instance.
|
||||
const defaultHostname = "github.com"
|
||||
|
||||
// localhost is the domain name of a local GitHub instance
|
||||
// Localhost is the domain name of a local GitHub instance.
|
||||
const localhost = "github.localhost"
|
||||
|
||||
// Default returns the host name of the default GitHub instance
|
||||
// TenancyHost is the domain name of a tenancy GitHub instance.
|
||||
const tenancyHost = "ghe.com"
|
||||
|
||||
// Default returns the host name of the default GitHub instance.
|
||||
func Default() string {
|
||||
return defaultHostname
|
||||
}
|
||||
|
||||
// IsEnterprise reports whether a non-normalized host name looks like a GHE instance
|
||||
// IsEnterprise reports whether a non-normalized host name looks like a GHE instance.
|
||||
func IsEnterprise(h string) bool {
|
||||
normalizedHostName := NormalizeHostname(h)
|
||||
return normalizedHostName != defaultHostname && normalizedHostName != localhost
|
||||
}
|
||||
|
||||
// IsTenancy reports whether a non-normalized host name looks like a tenancy instance.
|
||||
func IsTenancy(h string) bool {
|
||||
normalizedHostName := NormalizeHostname(h)
|
||||
return strings.HasSuffix(normalizedHostName, "."+tenancyHost)
|
||||
}
|
||||
|
||||
// TenantName extracts the tenant name from tenancy host name and
|
||||
// reports whether it found the tenant name.
|
||||
func TenantName(h string) (string, bool) {
|
||||
normalizedHostName := NormalizeHostname(h)
|
||||
return cutSuffix(normalizedHostName, "."+tenancyHost)
|
||||
}
|
||||
|
||||
func isGarage(h string) bool {
|
||||
return strings.EqualFold(h, "garage.github.com")
|
||||
}
|
||||
|
||||
// NormalizeHostname returns the canonical host name of a GitHub instance
|
||||
// NormalizeHostname returns the canonical host name of a GitHub instance.
|
||||
func NormalizeHostname(h string) string {
|
||||
hostname := strings.ToLower(h)
|
||||
if strings.HasSuffix(hostname, "."+defaultHostname) {
|
||||
return defaultHostname
|
||||
}
|
||||
|
||||
if strings.HasSuffix(hostname, "."+localhost) {
|
||||
return localhost
|
||||
}
|
||||
|
||||
if before, found := cutSuffix(hostname, "."+tenancyHost); found {
|
||||
idx := strings.LastIndex(before, ".")
|
||||
return fmt.Sprintf("%s.%s", before[idx+1:], tenancyHost)
|
||||
}
|
||||
return hostname
|
||||
}
|
||||
|
||||
|
|
@ -78,11 +97,9 @@ func RESTPrefix(hostname string) string {
|
|||
|
||||
func GistPrefix(hostname string) string {
|
||||
prefix := "https://"
|
||||
|
||||
if strings.EqualFold(hostname, localhost) {
|
||||
prefix = "http://"
|
||||
}
|
||||
|
||||
return prefix + GistHost(hostname)
|
||||
}
|
||||
|
||||
|
|
@ -105,3 +122,11 @@ func HostPrefix(hostname string) string {
|
|||
}
|
||||
return fmt.Sprintf("https://%s/", hostname)
|
||||
}
|
||||
|
||||
// Backport strings.CutSuffix from Go 1.20.
|
||||
func cutSuffix(s, suffix string) (string, bool) {
|
||||
if !strings.HasSuffix(s, suffix) {
|
||||
return s, false
|
||||
}
|
||||
return s[:len(s)-len(suffix)], true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,87 @@ func TestIsEnterprise(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIsTenancy(t *testing.T) {
|
||||
tests := []struct {
|
||||
host string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
host: "github.com",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
host: "github.localhost",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
host: "garage.github.com",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
host: "ghe.com",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
host: "tenant.ghe.com",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
host: "api.tenant.ghe.com",
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.host, func(t *testing.T) {
|
||||
if got := IsTenancy(tt.host); got != tt.want {
|
||||
t.Errorf("IsTenancy() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTenantName(t *testing.T) {
|
||||
tests := []struct {
|
||||
host string
|
||||
wantTenant string
|
||||
wantFound bool
|
||||
}{
|
||||
{
|
||||
host: "github.com",
|
||||
wantTenant: "github.com",
|
||||
},
|
||||
{
|
||||
host: "github.localhost",
|
||||
wantTenant: "github.localhost",
|
||||
},
|
||||
{
|
||||
host: "garage.github.com",
|
||||
wantTenant: "github.com",
|
||||
},
|
||||
{
|
||||
host: "ghe.com",
|
||||
wantTenant: "ghe.com",
|
||||
},
|
||||
{
|
||||
host: "tenant.ghe.com",
|
||||
wantTenant: "tenant",
|
||||
wantFound: true,
|
||||
},
|
||||
{
|
||||
host: "api.tenant.ghe.com",
|
||||
wantTenant: "tenant",
|
||||
wantFound: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.host, func(t *testing.T) {
|
||||
if tenant, found := TenantName(tt.host); tenant != tt.wantTenant || found != tt.wantFound {
|
||||
t.Errorf("TenantName(%v) = %v %v, want %v %v", tt.host, tenant, found, tt.wantTenant, tt.wantFound)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeHostname(t *testing.T) {
|
||||
tests := []struct {
|
||||
host string
|
||||
|
|
@ -90,6 +171,18 @@ func TestNormalizeHostname(t *testing.T) {
|
|||
host: "git.my.org",
|
||||
want: "git.my.org",
|
||||
},
|
||||
{
|
||||
host: "ghe.com",
|
||||
want: "ghe.com",
|
||||
},
|
||||
{
|
||||
host: "tenant.ghe.com",
|
||||
want: "tenant.ghe.com",
|
||||
},
|
||||
{
|
||||
host: "api.tenant.ghe.com",
|
||||
want: "tenant.ghe.com",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.host, func(t *testing.T) {
|
||||
|
|
@ -139,6 +232,7 @@ func TestHostnameValidator(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGraphQLEndpoint(t *testing.T) {
|
||||
tests := []struct {
|
||||
host string
|
||||
|
|
|
|||
|
|
@ -92,12 +92,13 @@ func GenerateRepoURL(repo Interface, p string, args ...interface{}) string {
|
|||
return baseURL
|
||||
}
|
||||
|
||||
// TODO there is a parallel implementation for non-isolated commands
|
||||
func FormatRemoteURL(repo Interface, protocol string) string {
|
||||
if protocol == "ssh" {
|
||||
if tenant, found := ghinstance.TenantName(repo.RepoHost()); found {
|
||||
return fmt.Sprintf("%s@%s:%s/%s.git", tenant, repo.RepoHost(), repo.RepoOwner(), repo.RepoName())
|
||||
}
|
||||
return fmt.Sprintf("git@%s:%s/%s.git", repo.RepoHost(), repo.RepoOwner(), repo.RepoName())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s/%s.git", ghinstance.HostPrefix(repo.RepoHost()), repo.RepoOwner(), repo.RepoName())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -220,3 +220,59 @@ func TestFromFullName(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatRemoteURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repoHost string
|
||||
repoOwner string
|
||||
repoName string
|
||||
protocol string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "https protocol",
|
||||
repoHost: "github.com",
|
||||
repoOwner: "owner",
|
||||
repoName: "name",
|
||||
protocol: "https",
|
||||
want: "https://github.com/owner/name.git",
|
||||
},
|
||||
{
|
||||
name: "https protocol local host",
|
||||
repoHost: "github.localhost",
|
||||
repoOwner: "owner",
|
||||
repoName: "name",
|
||||
protocol: "https",
|
||||
want: "http://github.localhost/owner/name.git",
|
||||
},
|
||||
{
|
||||
name: "ssh protocol",
|
||||
repoHost: "github.com",
|
||||
repoOwner: "owner",
|
||||
repoName: "name",
|
||||
protocol: "ssh",
|
||||
want: "git@github.com:owner/name.git",
|
||||
},
|
||||
{
|
||||
name: "ssh protocol tenancy host",
|
||||
repoHost: "tenant.ghe.com",
|
||||
repoOwner: "owner",
|
||||
repoName: "name",
|
||||
protocol: "ssh",
|
||||
want: "tenant@tenant.ghe.com:owner/name.git",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := ghRepo{
|
||||
hostname: tt.repoHost,
|
||||
owner: tt.repoOwner,
|
||||
name: tt.repoName,
|
||||
}
|
||||
if url := FormatRemoteURL(r, tt.protocol); url != tt.want {
|
||||
t.Errorf("expected url %q, got %q", tt.want, url)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue