github.com/goreleaser/goreleaser@v1.25.1/internal/git/config.go (about)

     1  package git
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/url"
     8  	"path"
     9  	"strings"
    10  
    11  	"github.com/caarlos0/log"
    12  	"github.com/goreleaser/goreleaser/pkg/config"
    13  )
    14  
    15  // ExtractRepoFromConfig gets the repo name from the Git config.
    16  func ExtractRepoFromConfig(ctx context.Context) (result config.Repo, err error) {
    17  	if !IsRepo(ctx) {
    18  		return result, errors.New("current folder is not a git repository")
    19  	}
    20  	out, err := Clean(Run(ctx, "ls-remote", "--get-url"))
    21  	if err != nil {
    22  		return result, fmt.Errorf("no remote configured to list refs from")
    23  	}
    24  	// This is a relative remote URL and requires some additional processing
    25  	if out == "." {
    26  		return extractRelativeRepoFromConfig(ctx)
    27  	}
    28  	log.WithField("rawurl", out).Debugf("got git url")
    29  	return ExtractRepoFromURL(out)
    30  }
    31  
    32  func extractRelativeRepoFromConfig(ctx context.Context) (result config.Repo, err error) {
    33  	out, err := Clean(Run(ctx, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"))
    34  	if err != nil || out == "" {
    35  		return result, fmt.Errorf("unable to get upstream while qualifying relative remote")
    36  	}
    37  	out, err = Clean(Run(ctx, "config", "--get", fmt.Sprintf("branch.%s.remote", out)))
    38  	if err != nil || out == "" {
    39  		return result, fmt.Errorf("unable to get upstream's remote while qualifying relative remote")
    40  	}
    41  	out, err = Clean(Run(ctx, "ls-remote", "--get-url", out))
    42  	if err != nil {
    43  		return result, fmt.Errorf("unable to get upstream while qualifying relative remote")
    44  	}
    45  	return ExtractRepoFromURL(out)
    46  }
    47  
    48  func ExtractRepoFromURL(rawurl string) (config.Repo, error) {
    49  	// removes the .git suffix and any new lines
    50  	s := strings.TrimSuffix(strings.TrimSpace(rawurl), ".git")
    51  
    52  	// if the URL contains a :, indicating a SSH config,
    53  	// remove all chars until it, including itself
    54  	// on HTTP and HTTPS URLs it will remove the http(s): prefix,
    55  	// which is ok. On SSH URLs the whole user@server will be removed,
    56  	// which is required.
    57  
    58  	// If the url contains more than 1 ':' character, assume we are doing an
    59  	// http URL with a username/password in it, and normalize the URL.
    60  	// Gitlab-CI uses this type of URL
    61  	if strings.Count(s, ":") == 1 {
    62  		s = s[strings.LastIndex(s, ":")+1:]
    63  	}
    64  
    65  	// now we can parse it with net/url
    66  	u, err := url.Parse(s)
    67  	if err != nil {
    68  		return config.Repo{
    69  			RawURL: rawurl,
    70  		}, err
    71  	}
    72  
    73  	// split the parsed url path by /, the last parts should be the owner and name
    74  	ss := strings.Split(strings.TrimPrefix(u.Path, "/"), "/")
    75  
    76  	// if empty, returns an error
    77  	if len(ss) == 0 || ss[0] == "" {
    78  		return config.Repo{
    79  			RawURL: rawurl,
    80  		}, fmt.Errorf("unsupported repository URL: %s", rawurl)
    81  	}
    82  
    83  	// if less than 2 parts, its likely not a valid repository, but we'll allow it.
    84  	if len(ss) < 2 {
    85  		return config.Repo{
    86  			RawURL: rawurl,
    87  			Owner:  ss[0],
    88  		}, nil
    89  	}
    90  	repo := config.Repo{
    91  		RawURL: rawurl,
    92  		Owner:  path.Join(ss[:len(ss)-1]...),
    93  		Name:   ss[len(ss)-1],
    94  	}
    95  	log.WithField("owner", repo.Owner).WithField("name", repo.Name).Debugf("parsed url")
    96  	return repo, nil
    97  }