github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/internal/ghrepo/repo.go (about)

     1  package ghrepo
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"strings"
     7  
     8  	"github.com/andrewhsu/cli/v2/git"
     9  	"github.com/andrewhsu/cli/v2/internal/ghinstance"
    10  )
    11  
    12  // Interface describes an object that represents a GitHub repository
    13  type Interface interface {
    14  	RepoName() string
    15  	RepoOwner() string
    16  	RepoHost() string
    17  }
    18  
    19  // New instantiates a GitHub repository from owner and name arguments
    20  func New(owner, repo string) Interface {
    21  	return NewWithHost(owner, repo, ghinstance.Default())
    22  }
    23  
    24  // NewWithHost is like New with an explicit host name
    25  func NewWithHost(owner, repo, hostname string) Interface {
    26  	return &ghRepo{
    27  		owner:    owner,
    28  		name:     repo,
    29  		hostname: normalizeHostname(hostname),
    30  	}
    31  }
    32  
    33  // FullName serializes a GitHub repository into an "OWNER/REPO" string
    34  func FullName(r Interface) string {
    35  	return fmt.Sprintf("%s/%s", r.RepoOwner(), r.RepoName())
    36  }
    37  
    38  var defaultHostOverride string
    39  
    40  func defaultHost() string {
    41  	if defaultHostOverride != "" {
    42  		return defaultHostOverride
    43  	}
    44  	return ghinstance.Default()
    45  }
    46  
    47  // SetDefaultHost overrides the default GitHub hostname for FromFullName.
    48  // TODO: remove after FromFullName approach is revisited
    49  func SetDefaultHost(host string) {
    50  	defaultHostOverride = host
    51  }
    52  
    53  // FromFullName extracts the GitHub repository information from the following
    54  // formats: "OWNER/REPO", "HOST/OWNER/REPO", and a full URL.
    55  func FromFullName(nwo string) (Interface, error) {
    56  	if git.IsURL(nwo) {
    57  		u, err := git.ParseURL(nwo)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		return FromURL(u)
    62  	}
    63  
    64  	parts := strings.SplitN(nwo, "/", 4)
    65  	for _, p := range parts {
    66  		if len(p) == 0 {
    67  			return nil, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, nwo)
    68  		}
    69  	}
    70  	switch len(parts) {
    71  	case 3:
    72  		return NewWithHost(parts[1], parts[2], parts[0]), nil
    73  	case 2:
    74  		return NewWithHost(parts[0], parts[1], defaultHost()), nil
    75  	default:
    76  		return nil, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, nwo)
    77  	}
    78  }
    79  
    80  // FromURL extracts the GitHub repository information from a git remote URL
    81  func FromURL(u *url.URL) (Interface, error) {
    82  	if u.Hostname() == "" {
    83  		return nil, fmt.Errorf("no hostname detected")
    84  	}
    85  
    86  	parts := strings.SplitN(strings.Trim(u.Path, "/"), "/", 3)
    87  	if len(parts) != 2 {
    88  		return nil, fmt.Errorf("invalid path: %s", u.Path)
    89  	}
    90  
    91  	return NewWithHost(parts[0], strings.TrimSuffix(parts[1], ".git"), u.Hostname()), nil
    92  }
    93  
    94  func normalizeHostname(h string) string {
    95  	return strings.ToLower(strings.TrimPrefix(h, "www."))
    96  }
    97  
    98  // IsSame compares two GitHub repositories
    99  func IsSame(a, b Interface) bool {
   100  	return strings.EqualFold(a.RepoOwner(), b.RepoOwner()) &&
   101  		strings.EqualFold(a.RepoName(), b.RepoName()) &&
   102  		normalizeHostname(a.RepoHost()) == normalizeHostname(b.RepoHost())
   103  }
   104  
   105  func GenerateRepoURL(repo Interface, p string, args ...interface{}) string {
   106  	baseURL := fmt.Sprintf("https://%s/%s/%s", repo.RepoHost(), repo.RepoOwner(), repo.RepoName())
   107  	if p != "" {
   108  		return baseURL + "/" + fmt.Sprintf(p, args...)
   109  	}
   110  	return baseURL
   111  }
   112  
   113  // TODO there is a parallel implementation for non-isolated commands
   114  func FormatRemoteURL(repo Interface, protocol string) string {
   115  	if protocol == "ssh" {
   116  		return fmt.Sprintf("git@%s:%s/%s.git", repo.RepoHost(), repo.RepoOwner(), repo.RepoName())
   117  	}
   118  
   119  	return fmt.Sprintf("https://%s/%s/%s.git", repo.RepoHost(), repo.RepoOwner(), repo.RepoName())
   120  }
   121  
   122  type ghRepo struct {
   123  	owner    string
   124  	name     string
   125  	hostname string
   126  }
   127  
   128  func (r ghRepo) RepoOwner() string {
   129  	return r.owner
   130  }
   131  
   132  func (r ghRepo) RepoName() string {
   133  	return r.name
   134  }
   135  
   136  func (r ghRepo) RepoHost() string {
   137  	return r.hostname
   138  }