* feat: allow snapshots on a folder that is not a git repo (#579)

* feat: allow running against a folder that is not a git repo

* test: cover clean err

* test: release: increase coverage

* test: fix race condition
This commit is contained in:
Carlos Alexandro Becker
2018-02-25 20:17:45 -03:00
committed by GitHub
parent 289e21f70c
commit 2ea883e0c4
9 changed files with 133 additions and 44 deletions
+5 -1
View File
@@ -34,5 +34,9 @@ func Run(args ...string) (string, error) {
// Clean the output
func Clean(output string, err error) (string, error) {
return strings.Replace(strings.Split(output, "\n")[0], "'", "", -1), err
output = strings.Replace(strings.Split(output, "\n")[0], "'", "", -1)
if err != nil {
err = errors.New(strings.TrimSuffix(err.Error(), "\n"))
}
return output, err
}
+9
View File
@@ -33,4 +33,13 @@ func TestClean(t *testing.T) {
out, err := Clean("asdasd 'ssadas'\nadasd", nil)
assert.NoError(t, err)
assert.Equal(t, "asdasd ssadas", out)
out, err = Clean(Run("command-that-dont-exist"))
assert.Error(t, err)
assert.Empty(t, out)
assert.Equal(
t,
"git: 'command-that-dont-exist' is not a git command. See 'git --help'.",
err.Error(),
)
}
+8 -5
View File
@@ -7,6 +7,7 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"sync"
"testing"
"github.com/goreleaser/goreleaser/config"
@@ -243,7 +244,7 @@ func TestRunPipe_ModeArchive(t *testing.T) {
Path: debfile.Name(),
})
var uploads = map[string]bool{}
var uploads sync.Map
// Dummy artifactories
mux.HandleFunc("/example-repo-local/goreleaser/1.0.0/bin.tar.gz", func(w http.ResponseWriter, r *http.Request) {
@@ -270,7 +271,7 @@ func TestRunPipe_ModeArchive(t *testing.T) {
},
"uri" : "http://127.0.0.1:56563/example-repo-local/goreleaser/bin.tar.gz"
}`)
uploads["targz"] = true
uploads.Store("targz", true)
})
mux.HandleFunc("/example-repo-local/goreleaser/1.0.0/bin.deb", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
@@ -296,12 +297,14 @@ func TestRunPipe_ModeArchive(t *testing.T) {
},
"uri" : "http://127.0.0.1:56563/example-repo-local/goreleaser/bin.deb"
}`)
uploads["deb"] = true
uploads.Store("deb", true)
})
assert.NoError(t, Pipe{}.Run(ctx))
assert.True(t, uploads["targz"], "tar.gz file was not uploaded")
assert.True(t, uploads["deb"], "deb file was not uploaded")
_, ok := uploads.Load("targz")
assert.True(t, ok, "tar.gz file was not uploaded")
_, ok = uploads.Load("deb")
assert.True(t, ok, "deb file was not uploaded")
}
func TestRunPipe_ArtifactoryDown(t *testing.T) {
+4
View File
@@ -32,3 +32,7 @@ func (e ErrWrongRef) Error() string {
// ErrNoTag happens if the underlying git repository doesn't contain any tags
// but no snapshot-release was requested.
var ErrNoTag = fmt.Errorf("git doesn't contain any tags. Either add a tag or use --snapshot")
// ErrNotRepository happens if you try to run goreleaser against a folder
// which is not a git repository.
var ErrNotRepository = fmt.Errorf("current folder is not a git repository")
+59 -31
View File
@@ -21,28 +21,57 @@ func (Pipe) String() string {
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) (err error) {
tag, commit, err := getInfo()
func (Pipe) Run(ctx *context.Context) error {
info, err := getInfo(ctx)
if err != nil {
return
return err
}
if tag == "" && !ctx.Snapshot {
return ErrNoTag
ctx.Git = info
log.Infof("releasing %s, commit %s", info.CurrentTag, info.Commit)
if err := setVersion(ctx); err != nil {
return err
}
ctx.Git = context.GitInfo{
CurrentTag: tag,
Commit: commit,
}
log.Infof("releasing %s, commit %s", tag, commit)
if err = setVersion(ctx, tag, commit); err != nil {
return
}
return validate(ctx, commit, tag)
return validate(ctx)
}
func setVersion(ctx *context.Context, tag, commit string) (err error) {
func getInfo(ctx *context.Context) (context.GitInfo, error) {
if !git.IsRepo() && ctx.Snapshot {
log.Warn("running against a folder that is not a git repo")
return context.GitInfo{
CurrentTag: "v0.0.0",
Commit: "none",
}, nil
}
if !git.IsRepo() {
return context.GitInfo{}, ErrNotRepository
}
info, err := getGitInfo(ctx)
if err != nil && ctx.Snapshot {
return info, nil
}
return info, err
}
func getGitInfo(ctx *context.Context) (context.GitInfo, error) {
commit, err := getCommit()
if err != nil {
return context.GitInfo{}, errors.Wrap(err, "couldn't get current commit")
}
tag, err := getTag()
if err != nil {
return context.GitInfo{
Commit: commit,
}, ErrNoTag
}
return context.GitInfo{
CurrentTag: tag,
Commit: commit,
}, nil
}
func setVersion(ctx *context.Context) error {
if ctx.Snapshot {
snapshotName, err := getSnapshotName(ctx, tag, commit)
snapshotName, err := getSnapshotName(ctx)
if err != nil {
return errors.Wrap(err, "failed to generate snapshot name")
}
@@ -50,8 +79,8 @@ func setVersion(ctx *context.Context, tag, commit string) (err error) {
return nil
}
// removes usual `v` prefix
ctx.Version = strings.TrimPrefix(tag, "v")
return
ctx.Version = strings.TrimPrefix(ctx.Git.CurrentTag, "v")
return nil
}
type snapshotNameData struct {
@@ -60,22 +89,22 @@ type snapshotNameData struct {
Timestamp int64
}
func getSnapshotName(ctx *context.Context, tag, commit string) (string, error) {
func getSnapshotName(ctx *context.Context) (string, error) {
tmpl, err := template.New("snapshot").Parse(ctx.Config.Snapshot.NameTemplate)
var out bytes.Buffer
if err != nil {
return "", err
}
var data = snapshotNameData{
Commit: commit,
Tag: tag,
Commit: ctx.Git.Commit,
Tag: ctx.Git.CurrentTag,
Timestamp: time.Now().Unix(),
}
err = tmpl.Execute(&out, data)
return out.String(), err
}
func validate(ctx *context.Context, commit, tag string) error {
func validate(ctx *context.Context) error {
if ctx.Snapshot {
return nil
}
@@ -86,18 +115,17 @@ func validate(ctx *context.Context, commit, tag string) error {
if !regexp.MustCompile("^[0-9.]+").MatchString(ctx.Version) {
return ErrInvalidVersionFormat{ctx.Version}
}
_, err = git.Clean(git.Run("describe", "--exact-match", "--tags", "--match", tag))
_, err = git.Clean(git.Run("describe", "--exact-match", "--tags", "--match", ctx.Git.CurrentTag))
if err != nil {
return ErrWrongRef{commit, tag}
return ErrWrongRef{ctx.Git.Commit, ctx.Git.CurrentTag}
}
return nil
}
func getInfo() (tag, commit string, err error) {
tag, err = git.Clean(git.Run("describe", "--tags", "--abbrev=0"))
if err != nil {
log.WithError(err).Info("failed to retrieve current tag")
}
commit, err = git.Clean(git.Run("show", "--format='%H'", "HEAD"))
return
func getCommit() (string, error) {
return git.Clean(git.Run("show", "--format='%H'", "HEAD"))
}
func getTag() (string, error) {
return git.Clean(git.Run("describe", "--tags", "--abbrev=0"))
}
+22 -3
View File
@@ -22,7 +22,7 @@ func TestNotAGitFolder(t *testing.T) {
var ctx = &context.Context{
Config: config.Project{},
}
assert.EqualError(t, Pipe{}.Run(ctx), "fatal: Not a git repository (or any of the parent directories): .git\n")
assert.EqualError(t, Pipe{}.Run(ctx), ErrNotRepository.Error())
}
func TestSingleCommit(t *testing.T) {
@@ -142,7 +142,7 @@ func TestValidState(t *testing.T) {
assert.Equal(t, "v0.0.2", ctx.Git.CurrentTag)
}
func TestSnapshot(t *testing.T) {
func TestSnapshotNoTags(t *testing.T) {
_, back := testlib.Mktmp(t)
defer back()
testlib.GitInit(t)
@@ -153,4 +153,23 @@ func TestSnapshot(t *testing.T) {
assert.NoError(t, Pipe{}.Run(ctx))
}
// TODO: missing a test case for a dirty git tree and snapshot
func TestSnapshotWithoutRepo(t *testing.T) {
_, back := testlib.Mktmp(t)
defer back()
var ctx = context.New(config.Project{})
ctx.Snapshot = true
assert.NoError(t, Pipe{}.Run(ctx))
}
func TestSnapshotDirty(t *testing.T) {
folder, back := testlib.Mktmp(t)
defer back()
testlib.GitInit(t)
testlib.GitAdd(t)
testlib.GitCommit(t, "whatever")
testlib.GitTag(t, "v0.0.1")
assert.NoError(t, ioutil.WriteFile(filepath.Join(folder, "foo"), []byte("foobar"), 0644))
var ctx = context.New(config.Project{})
ctx.Snapshot = true
assert.NoError(t, Pipe{}.Run(ctx))
}
+1 -1
View File
@@ -28,7 +28,7 @@ func (Pipe) Default(ctx *context.Context) error {
return nil
}
repo, err := remoteRepo()
if err != nil {
if err != nil && !ctx.Snapshot {
return err
}
ctx.Config.Release.GitHub = repo
+23 -2
View File
@@ -174,11 +174,32 @@ func TestDefaultFilled(t *testing.T) {
func TestDefaultNotAGitRepo(t *testing.T) {
_, back := testlib.Mktmp(t)
defer back()
testlib.GitInit(t)
var ctx = &context.Context{
Config: config.Project{},
}
assert.Error(t, Pipe{}.Default(ctx))
assert.EqualError(t, Pipe{}.Default(ctx), "current folder is not a git repository")
assert.Empty(t, ctx.Config.Release.GitHub.String())
}
func TestDefaultGitRepoWithoutOrigin(t *testing.T) {
_, back := testlib.Mktmp(t)
defer back()
var ctx = &context.Context{
Config: config.Project{},
}
testlib.GitInit(t)
assert.EqualError(t, Pipe{}.Default(ctx), "repository doesn't have an `origin` remote")
assert.Empty(t, ctx.Config.Release.GitHub.String())
}
func TestDefaultNotAGitRepoSnapshot(t *testing.T) {
_, back := testlib.Mktmp(t)
defer back()
var ctx = &context.Context{
Config: config.Project{},
}
ctx.Snapshot = true
assert.NoError(t, Pipe{}.Default(ctx))
assert.Empty(t, ctx.Config.Release.GitHub.String())
}
+2 -1
View File
@@ -1,6 +1,7 @@
package release
import (
"fmt"
"strings"
"github.com/goreleaser/goreleaser/config"
@@ -15,7 +16,7 @@ func remoteRepo() (result config.Repo, err error) {
}
out, err := git.Run("config", "--get", "remote.origin.url")
if err != nil {
return result, errors.Wrap(err, "repository doesn't have an `origin` remote")
return result, fmt.Errorf("repository doesn't have an `origin` remote")
}
return extractRepoFromURL(out), nil
}