...

Source file src/github.com/cli/go-gh/v2/pkg/repository/repository.go

Documentation: github.com/cli/go-gh/v2/pkg/repository

     1  // Package repository is a set of types and functions for modeling and
     2  // interacting with GitHub repositories.
     3  package repository
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"strings"
    10  
    11  	"github.com/cli/go-gh/v2/internal/git"
    12  	"github.com/cli/go-gh/v2/pkg/auth"
    13  	"github.com/cli/go-gh/v2/pkg/ssh"
    14  )
    15  
    16  // Repository holds information representing a GitHub repository.
    17  type Repository struct {
    18  	Host  string
    19  	Name  string
    20  	Owner string
    21  }
    22  
    23  // Parse extracts the repository information from the following
    24  // string formats: "OWNER/REPO", "HOST/OWNER/REPO", and a full URL.
    25  // If the format does not specify a host, use the config to determine a host.
    26  func Parse(s string) (Repository, error) {
    27  	var r Repository
    28  
    29  	if git.IsURL(s) {
    30  		u, err := git.ParseURL(s)
    31  		if err != nil {
    32  			return r, err
    33  		}
    34  
    35  		host, owner, name, err := git.RepoInfoFromURL(u)
    36  		if err != nil {
    37  			return r, err
    38  		}
    39  
    40  		r.Host = host
    41  		r.Name = name
    42  		r.Owner = owner
    43  
    44  		return r, nil
    45  	}
    46  
    47  	parts := strings.SplitN(s, "/", 4)
    48  	for _, p := range parts {
    49  		if len(p) == 0 {
    50  			return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
    51  		}
    52  	}
    53  
    54  	switch len(parts) {
    55  	case 3:
    56  		r.Host = parts[0]
    57  		r.Owner = parts[1]
    58  		r.Name = parts[2]
    59  		return r, nil
    60  	case 2:
    61  		r.Host, _ = auth.DefaultHost()
    62  		r.Owner = parts[0]
    63  		r.Name = parts[1]
    64  		return r, nil
    65  	default:
    66  		return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
    67  	}
    68  }
    69  
    70  // Parse extracts the repository information from the following
    71  // string formats: "OWNER/REPO", "HOST/OWNER/REPO", and a full URL.
    72  // If the format does not specify a host, use the host provided.
    73  func ParseWithHost(s, host string) (Repository, error) {
    74  	var r Repository
    75  
    76  	if git.IsURL(s) {
    77  		u, err := git.ParseURL(s)
    78  		if err != nil {
    79  			return r, err
    80  		}
    81  
    82  		host, owner, name, err := git.RepoInfoFromURL(u)
    83  		if err != nil {
    84  			return r, err
    85  		}
    86  
    87  		r.Host = host
    88  		r.Owner = owner
    89  		r.Name = name
    90  
    91  		return r, nil
    92  	}
    93  
    94  	parts := strings.SplitN(s, "/", 4)
    95  	for _, p := range parts {
    96  		if len(p) == 0 {
    97  			return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
    98  		}
    99  	}
   100  
   101  	switch len(parts) {
   102  	case 3:
   103  		r.Host = parts[0]
   104  		r.Owner = parts[1]
   105  		r.Name = parts[2]
   106  		return r, nil
   107  	case 2:
   108  		r.Host = host
   109  		r.Owner = parts[0]
   110  		r.Name = parts[1]
   111  		return r, nil
   112  	default:
   113  		return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
   114  	}
   115  }
   116  
   117  // Current uses git remotes to determine the GitHub repository
   118  // the current directory is tracking.
   119  func Current() (Repository, error) {
   120  	var r Repository
   121  
   122  	override := os.Getenv("GH_REPO")
   123  	if override != "" {
   124  		return Parse(override)
   125  	}
   126  
   127  	remotes, err := git.Remotes()
   128  	if err != nil {
   129  		return r, err
   130  	}
   131  	if len(remotes) == 0 {
   132  		return r, errors.New("unable to determine current repository, no git remotes configured for this repository")
   133  	}
   134  
   135  	translator := ssh.NewTranslator()
   136  	for _, r := range remotes {
   137  		if r.FetchURL != nil {
   138  			r.FetchURL = translator.Translate(r.FetchURL)
   139  		}
   140  		if r.PushURL != nil {
   141  			r.PushURL = translator.Translate(r.PushURL)
   142  		}
   143  	}
   144  
   145  	hosts := auth.KnownHosts()
   146  
   147  	filteredRemotes := remotes.FilterByHosts(hosts)
   148  	if len(filteredRemotes) == 0 {
   149  		return r, errors.New("unable to determine current repository, none of the git remotes configured for this repository point to a known GitHub host")
   150  	}
   151  
   152  	rem := filteredRemotes[0]
   153  	r.Host = rem.Host
   154  	r.Owner = rem.Owner
   155  	r.Name = rem.Repo
   156  
   157  	return r, nil
   158  }
   159  

View as plain text