mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-03-17 20:47:50 +02:00
feat: allow git remote urls from non-scm sources (#3088)
basically allows to use goreleaser against a repo with a git url without both owner and repo name. closes #3060 closes #3058 Signed-off-by: Carlos A Becker <caarlos0@gmail.com>
This commit is contained in:
parent
a02cbca273
commit
53b1ee07cf
@ -16,7 +16,7 @@ func ExtractRepoFromConfig(ctx context.Context) (result config.Repo, err error)
|
||||
if !IsRepo(ctx) {
|
||||
return result, errors.New("current folder is not a git repository")
|
||||
}
|
||||
out, err := Run(ctx, "ls-remote", "--get-url")
|
||||
out, err := Clean(Run(ctx, "ls-remote", "--get-url"))
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("no remote configured to list refs from")
|
||||
}
|
||||
@ -44,19 +44,32 @@ func ExtractRepoFromURL(rawurl string) (config.Repo, error) {
|
||||
// now we can parse it with net/url
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return config.Repo{}, err
|
||||
return config.Repo{
|
||||
RawURL: rawurl,
|
||||
}, err
|
||||
}
|
||||
|
||||
// split the parsed url path by /, the last parts should be the owner and name
|
||||
ss := strings.Split(strings.TrimPrefix(u.Path, "/"), "/")
|
||||
|
||||
// if less than 2 parts, its likely not a valid repository
|
||||
// if empty, returns an error
|
||||
if len(ss) == 0 || ss[0] == "" {
|
||||
return config.Repo{
|
||||
RawURL: rawurl,
|
||||
}, fmt.Errorf("unsupported repository URL: %s", rawurl)
|
||||
}
|
||||
|
||||
// if less than 2 parts, its likely not a valid repository, but we'll allow it.
|
||||
if len(ss) < 2 {
|
||||
return config.Repo{}, fmt.Errorf("unsupported repository URL: %s", rawurl)
|
||||
return config.Repo{
|
||||
RawURL: rawurl,
|
||||
Owner: ss[0],
|
||||
}, nil
|
||||
}
|
||||
repo := config.Repo{
|
||||
Owner: strings.Join(ss[:len(ss)-1], "/"),
|
||||
Name: ss[len(ss)-1],
|
||||
RawURL: rawurl,
|
||||
Owner: strings.Join(ss[:len(ss)-1], "/"),
|
||||
Name: ss[len(ss)-1],
|
||||
}
|
||||
log.WithField("owner", repo.Owner).WithField("name", repo.Name).Debugf("parsed url")
|
||||
return repo, nil
|
||||
|
@ -60,6 +60,8 @@ func TestExtractRepoFromURL(t *testing.T) {
|
||||
repo, err := git.ExtractRepoFromURL(url)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "goreleaser/goreleaser", repo.String())
|
||||
require.NoError(t, repo.CheckSCM())
|
||||
require.Equal(t, url, repo.RawURL)
|
||||
})
|
||||
}
|
||||
|
||||
@ -73,18 +75,35 @@ func TestExtractRepoFromURL(t *testing.T) {
|
||||
repo, err := git.ExtractRepoFromURL(url)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "group/nested/goreleaser/goreleaser", repo.String())
|
||||
require.NoError(t, repo.CheckSCM())
|
||||
require.Equal(t, url, repo.RawURL)
|
||||
})
|
||||
}
|
||||
|
||||
// invalid urls
|
||||
for _, url := range []string{
|
||||
"git@gist.github.com:someid.git",
|
||||
"https://gist.github.com/someid.git",
|
||||
} {
|
||||
t.Run(url, func(t *testing.T) {
|
||||
repo, err := git.ExtractRepoFromURL(url)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "someid", repo.String())
|
||||
require.Error(t, repo.CheckSCM())
|
||||
require.Equal(t, url, repo.RawURL)
|
||||
})
|
||||
}
|
||||
|
||||
// invalid urls
|
||||
for _, url := range []string{
|
||||
"git@gist.github.com:",
|
||||
"https://gist.github.com/",
|
||||
} {
|
||||
t.Run(url, func(t *testing.T) {
|
||||
repo, err := git.ExtractRepoFromURL(url)
|
||||
require.EqualError(t, err, "unsupported repository URL: "+url)
|
||||
require.Equal(t, "", repo.String())
|
||||
require.Error(t, repo.CheckSCM())
|
||||
require.Equal(t, url, repo.RawURL)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -287,6 +287,9 @@ func newGithubChangeloger(ctx *context.Context) (changeloger, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := repo.CheckSCM(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &githubNativeChangeloger{
|
||||
client: cli,
|
||||
repo: client.Repo{
|
||||
@ -305,6 +308,9 @@ func newSCMChangeloger(ctx *context.Context) (changeloger, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := repo.CheckSCM(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &scmChangeloger{
|
||||
client: cli,
|
||||
repo: client.Repo{
|
||||
|
@ -536,6 +536,21 @@ func TestGetChangeloger(t *testing.T) {
|
||||
require.IsType(t, c, &githubNativeChangeloger{})
|
||||
})
|
||||
|
||||
t.Run(useGitHubNative+"-invalid-repo", func(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
testlib.GitRemoteAdd(t, "https://gist.github.com/")
|
||||
ctx := context.New(config.Project{
|
||||
Changelog: config.Changelog{
|
||||
Use: useGitHubNative,
|
||||
},
|
||||
})
|
||||
ctx.TokenType = context.TokenTypeGitHub
|
||||
c, err := getChangeloger(ctx)
|
||||
require.EqualError(t, err, "unsupported repository URL: https://gist.github.com/")
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run(useGitLab, func(t *testing.T) {
|
||||
ctx := context.New(config.Project{
|
||||
Changelog: config.Changelog{
|
||||
@ -548,6 +563,21 @@ func TestGetChangeloger(t *testing.T) {
|
||||
require.IsType(t, c, &scmChangeloger{})
|
||||
})
|
||||
|
||||
t.Run(useGitHub+"-invalid-repo", func(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
testlib.GitRemoteAdd(t, "https://gist.github.com/")
|
||||
ctx := context.New(config.Project{
|
||||
Changelog: config.Changelog{
|
||||
Use: useGitHub,
|
||||
},
|
||||
})
|
||||
ctx.TokenType = context.TokenTypeGitHub
|
||||
c, err := getChangeloger(ctx)
|
||||
require.EqualError(t, err, "unsupported repository URL: https://gist.github.com/")
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run("invalid", func(t *testing.T) {
|
||||
c, err := getChangeloger(context.New(config.Project{
|
||||
Changelog: config.Changelog{
|
||||
|
@ -29,10 +29,12 @@ func (Pipe) Default(ctx *context.Context) error {
|
||||
|
||||
if milestone.Repo.Name == "" {
|
||||
repo, err := git.ExtractRepoFromConfig(ctx)
|
||||
|
||||
if err != nil && !ctx.Snapshot {
|
||||
return err
|
||||
}
|
||||
if err := repo.CheckSCM(); err != nil && !ctx.Snapshot {
|
||||
return err
|
||||
}
|
||||
|
||||
milestone.Repo = repo
|
||||
}
|
||||
|
@ -31,6 +31,18 @@ func TestDefaultWithRepoConfig(t *testing.T) {
|
||||
require.Equal(t, "configowner", ctx.Config.Milestones[0].Repo.Owner)
|
||||
}
|
||||
|
||||
func TestDefaultWithInvalidRemote(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
testlib.GitRemoteAdd(t, "git@github.com:githubowner.git")
|
||||
|
||||
ctx := context.New(config.Project{
|
||||
Milestones: []config.Milestone{{}},
|
||||
})
|
||||
ctx.TokenType = context.TokenTypeGitHub
|
||||
require.Error(t, Pipe{}.Default(ctx))
|
||||
}
|
||||
|
||||
func TestDefaultWithRepoRemote(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/goreleaser/goreleaser/internal/extrafiles"
|
||||
"github.com/goreleaser/goreleaser/internal/git"
|
||||
"github.com/goreleaser/goreleaser/internal/semerrgroup"
|
||||
"github.com/goreleaser/goreleaser/pkg/config"
|
||||
"github.com/goreleaser/goreleaser/pkg/context"
|
||||
)
|
||||
|
||||
@ -48,7 +49,7 @@ func (Pipe) Default(ctx *context.Context) error {
|
||||
switch ctx.TokenType {
|
||||
case context.TokenTypeGitLab:
|
||||
if ctx.Config.Release.GitLab.Name == "" {
|
||||
repo, err := git.ExtractRepoFromConfig(ctx)
|
||||
repo, err := getRepository(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -63,7 +64,7 @@ func (Pipe) Default(ctx *context.Context) error {
|
||||
)
|
||||
case context.TokenTypeGitea:
|
||||
if ctx.Config.Release.Gitea.Name == "" {
|
||||
repo, err := git.ExtractRepoFromConfig(ctx)
|
||||
repo, err := getRepository(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -79,7 +80,7 @@ func (Pipe) Default(ctx *context.Context) error {
|
||||
default:
|
||||
// We keep github as default for now
|
||||
if ctx.Config.Release.GitHub.Name == "" {
|
||||
repo, err := git.ExtractRepoFromConfig(ctx)
|
||||
repo, err := getRepository(ctx)
|
||||
if err != nil && !ctx.Snapshot {
|
||||
return err
|
||||
}
|
||||
@ -109,6 +110,17 @@ func (Pipe) Default(ctx *context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRepository(ctx *context.Context) (config.Repo, error) {
|
||||
repo, err := git.ExtractRepoFromConfig(ctx)
|
||||
if err != nil {
|
||||
return config.Repo{}, err
|
||||
}
|
||||
if err := repo.CheckSCM(); err != nil {
|
||||
return config.Repo{}, err
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
// Publish the release.
|
||||
func (Pipe) Publish(ctx *context.Context) error {
|
||||
c, err := client.New(ctx)
|
||||
|
@ -354,6 +354,18 @@ func TestDefault(t *testing.T) {
|
||||
require.Equal(t, "https://github.com/goreleaser/goreleaser/releases/tag/v1.0.0", ctx.ReleaseURL)
|
||||
}
|
||||
|
||||
func TestDefaultInvalidURL(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
testlib.GitRemoteAdd(t, "git@github.com:goreleaser.git")
|
||||
|
||||
ctx := context.New(config.Project{})
|
||||
ctx.TokenType = context.TokenTypeGitHub
|
||||
ctx.Config.GitHubURLs.Download = "https://github.com"
|
||||
ctx.Git.CurrentTag = "v1.0.0"
|
||||
require.Error(t, Pipe{}.Default(ctx))
|
||||
}
|
||||
|
||||
func TestDefaultWithGitlab(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
@ -369,6 +381,18 @@ func TestDefaultWithGitlab(t *testing.T) {
|
||||
require.Equal(t, "https://gitlab.com/gitlabowner/gitlabrepo/-/releases/v1.0.0", ctx.ReleaseURL)
|
||||
}
|
||||
|
||||
func TestDefaultWithGitlabInvalidURL(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
testlib.GitRemoteAdd(t, "git@gitlab.com:gitlabrepo.git")
|
||||
|
||||
ctx := context.New(config.Project{})
|
||||
ctx.TokenType = context.TokenTypeGitLab
|
||||
ctx.Config.GitLabURLs.Download = "https://gitlab.com"
|
||||
ctx.Git.CurrentTag = "v1.0.0"
|
||||
require.Error(t, Pipe{}.Default(ctx))
|
||||
}
|
||||
|
||||
func TestDefaultWithGitea(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
@ -384,6 +408,18 @@ func TestDefaultWithGitea(t *testing.T) {
|
||||
require.Equal(t, "https://git.honk.com/giteaowner/gitearepo/releases/tag/v1.0.0", ctx.ReleaseURL)
|
||||
}
|
||||
|
||||
func TestDefaultWithGiteaInvalidURL(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
testlib.GitRemoteAdd(t, "git@gitea.example.com:gitearepo.git")
|
||||
|
||||
ctx := context.New(config.Project{})
|
||||
ctx.TokenType = context.TokenTypeGitea
|
||||
ctx.Config.GiteaURLs.Download = "https://git.honk.com"
|
||||
ctx.Git.CurrentTag = "v1.0.0"
|
||||
require.Error(t, Pipe{}.Default(ctx))
|
||||
}
|
||||
|
||||
func TestDefaultPreRelease(t *testing.T) {
|
||||
testlib.Mktmp(t)
|
||||
testlib.GitInit(t)
|
||||
|
@ -4,6 +4,7 @@ package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
@ -42,16 +43,30 @@ type GiteaURLs struct {
|
||||
// Repo represents any kind of repo (github, gitlab, etc).
|
||||
// to upload releases into.
|
||||
type Repo struct {
|
||||
Owner string `yaml:"owner,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Owner string `yaml:"owner,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
RawURL string `yaml:"-"`
|
||||
}
|
||||
|
||||
// String of the repo, e.g. owner/name.
|
||||
func (r Repo) String() string {
|
||||
if r.Owner == "" && r.Name == "" {
|
||||
return ""
|
||||
if r.isSCM() {
|
||||
return r.Owner + "/" + r.Name
|
||||
}
|
||||
return r.Owner + "/" + r.Name
|
||||
return r.Owner
|
||||
}
|
||||
|
||||
// CheckSCM returns an error if the given url is not a valid scm url.
|
||||
func (r Repo) CheckSCM() error {
|
||||
if r.isSCM() {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid scm url: %s", r.RawURL)
|
||||
}
|
||||
|
||||
// isSCM returns true if the repo has both an owner and name.
|
||||
func (r Repo) isSCM() bool {
|
||||
return r.Owner != "" && r.Name != ""
|
||||
}
|
||||
|
||||
// RepoRef represents any kind of repo which may differ
|
||||
|
Loading…
x
Reference in New Issue
Block a user