Repository: goreleaser/goreleaser
Pull request #895 (2018-12-13 12:12:24)

fix: snapshot version handling
<!--

Hi, thanks for contributing!

Please make sure you read our CONTRIBUTING guide.

Please fill the fields above:

-->

<!-- If applied, this commit will... -->
Make sure there is always a `ctx.Version` when snapshotting.

<!-- Why is this change being made? -->
if `config.snapshot.name_template` was empty, the default was being set after the template (which was empty) was already evaluated, leaving the user with an empty `ctx.Version`.

<!-- # Provide links to any relevant tickets, URLs or other resources -->
For some reason, snapcraft just now started to complain about that.

codecov-io: # [Codecov](https://codecov.io/gh/goreleaser/goreleaser/pull/895?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@513473b`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/goreleaser/goreleaser/pull/895/graphs/tree.svg?width=650&token=3bJvv6b7hN&height=150&src=pr)](https://codecov.io/gh/goreleaser/goreleaser/pull/895?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master     #895   +/-   ##
=========================================
  Coverage          ?   88.12%           
=========================================
  Files             ?       48           
  Lines             ?     2367           
  Branches          ?        0           
=========================================
  Hits              ?     2086           
  Misses            ?      222           
  Partials          ?       59
```


| [Impacted Files](https://codecov.io/gh/goreleaser/goreleaser/pull/895?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [internal/pipe/git/git.go](https://codecov.io/gh/goreleaser/goreleaser/pull/895/diff?src=pr&el=tree#diff-aW50ZXJuYWwvcGlwZS9naXQvZ2l0Lmdv) | `92.5% <100%> (ø)` | |
| [internal/pipe/snapcraft/snapcraft.go](https://codecov.io/gh/goreleaser/goreleaser/pull/895/diff?src=pr&el=tree#diff-aW50ZXJuYWwvcGlwZS9zbmFwY3JhZnQvc25hcGNyYWZ0Lmdv) | `87.8% <100%> (ø)` | |
| [internal/pipe/snapshot/snapshot.go](https://codecov.io/gh/goreleaser/goreleaser/pull/895/diff?src=pr&el=tree#diff-aW50ZXJuYWwvcGlwZS9zbmFwc2hvdC9zbmFwc2hvdC5nbw==) | `100% <100%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goreleaser/goreleaser/pull/895?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goreleaser/goreleaser/pull/895?src=pr&el=footer). Last update [513473b...74a3f94](https://codecov.io/gh/goreleaser/goreleaser/pull/895?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

caarlos0: closes #894

Patch:
diff --git a/.travis.yml b/.travis.yml
index 238764de..8b25b56a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@ install:
   - sudo snap install snapcraft --classic
 script:
   - make ci
-  - test -n "$TRAVIS_TAG" || go run main.go --snapshot
+  - test -n "$TRAVIS_TAG" || go run main.go --snapshot --debug
 after_success:
   - bash <(curl -s https://codecov.io/bash)
   - make static
diff --git a/internal/pipe/git/git.go b/internal/pipe/git/git.go
index 60614043..71e04371 100644
--- a/internal/pipe/git/git.go
+++ b/internal/pipe/git/git.go
@@ -9,7 +9,6 @@ import (
 	"github.com/goreleaser/goreleaser/internal/deprecate"
 	"github.com/goreleaser/goreleaser/internal/git"
 	"github.com/goreleaser/goreleaser/internal/pipe"
-	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/context"
 	"github.com/pkg/errors"
 )
@@ -35,9 +34,7 @@ func (Pipe) Run(ctx *context.Context) error {
 	}
 	ctx.Git = info
 	log.Infof("releasing %s, commit %s", info.CurrentTag, info.Commit)
-	if err := setVersion(ctx); err != nil {
-		return err
-	}
+	ctx.Version = strings.TrimPrefix(ctx.Git.CurrentTag, "v")
 	return validate(ctx)
 }
 
@@ -104,20 +101,6 @@ func getGitInfo(ctx *context.Context) (context.GitInfo, error) {
 	}, nil
 }
 
-func setVersion(ctx *context.Context) error {
-	if ctx.Snapshot {
-		snapshotName, err := tmpl.New(ctx).Apply(ctx.Config.Snapshot.NameTemplate)
-		if err != nil {
-			return errors.Wrap(err, "failed to generate snapshot name")
-		}
-		ctx.Version = snapshotName
-		return nil
-	}
-	// removes usual `v` prefix
-	ctx.Version = strings.TrimPrefix(ctx.Git.CurrentTag, "v")
-	return nil
-}
-
 func validate(ctx *context.Context) error {
 	if ctx.Snapshot {
 		return pipe.ErrSnapshotEnabled
diff --git a/internal/pipe/snapcraft/snapcraft.go b/internal/pipe/snapcraft/snapcraft.go
index d08e1175..76b24685 100644
--- a/internal/pipe/snapcraft/snapcraft.go
+++ b/internal/pipe/snapcraft/snapcraft.go
@@ -150,6 +150,8 @@ func create(ctx *context.Context, arch string, binaries []artifact.Artifact) err
 		metadata.Name = ctx.Config.Snapcraft.Name
 	}
 
+	log.Debugf("metadata: %+v", metadata)
+
 	for _, binary := range binaries {
 		log.WithField("path", binary.Path).
 			WithField("name", binary.Name).
@@ -168,6 +170,9 @@ func create(ctx *context.Context, arch string, binaries []artifact.Artifact) err
 		metadata.Apps[binary.Name] = appMetadata
 
 		destBinaryPath := filepath.Join(primeDir, filepath.Base(binary.Path))
+		log.WithField("src", binary.Path).
+			WithField("dst", destBinaryPath).
+			Debug("linking")
 		if err = os.Link(binary.Path, destBinaryPath); err != nil {
 			return errors.Wrap(err, "failed to link binary")
 		}
diff --git a/internal/pipe/snapshot/snapshot.go b/internal/pipe/snapshot/snapshot.go
index 56e341a2..84c135fd 100644
--- a/internal/pipe/snapshot/snapshot.go
+++ b/internal/pipe/snapshot/snapshot.go
@@ -1,7 +1,14 @@
 // Package snapshot provides the snapshoting functionality to goreleaser.
 package snapshot
 
-import "github.com/goreleaser/goreleaser/pkg/context"
+import (
+	"fmt"
+
+	"github.com/goreleaser/goreleaser/internal/pipe"
+	"github.com/goreleaser/goreleaser/internal/tmpl"
+	"github.com/goreleaser/goreleaser/pkg/context"
+	"github.com/pkg/errors"
+)
 
 // Pipe for checksums
 type Pipe struct{}
@@ -13,7 +20,22 @@ func (Pipe) String() string {
 // Default sets the pipe defaults
 func (Pipe) Default(ctx *context.Context) error {
 	if ctx.Config.Snapshot.NameTemplate == "" {
-		ctx.Config.Snapshot.NameTemplate = "SNAPSHOT-{{ .Commit }}"
+		ctx.Config.Snapshot.NameTemplate = "SNAPSHOT-{{ .ShortCommit }}"
+	}
+	return nil
+}
+
+func (Pipe) Run(ctx *context.Context) error {
+	if !ctx.Snapshot {
+		return pipe.Skip("not a snapshot")
+	}
+	name, err := tmpl.New(ctx).Apply(ctx.Config.Snapshot.NameTemplate)
+	if err != nil {
+		return errors.Wrap(err, "failed to generate snapshot name")
+	}
+	if name == "" {
+		return fmt.Errorf("empty snapshot name")
 	}
+	ctx.Version = name
 	return nil
 }
diff --git a/internal/pipeline/pipeline.go b/internal/pipeline/pipeline.go
index 10bbe065..bf736424 100644
--- a/internal/pipeline/pipeline.go
+++ b/internal/pipeline/pipeline.go
@@ -19,6 +19,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/pipe/publish"
 	"github.com/goreleaser/goreleaser/internal/pipe/sign"
 	"github.com/goreleaser/goreleaser/internal/pipe/snapcraft"
+	"github.com/goreleaser/goreleaser/internal/pipe/snapshot"
 	"github.com/goreleaser/goreleaser/pkg/context"
 )
 
@@ -36,6 +37,7 @@ var Pipeline = []Piper{
 	before.Pipe{},          // run global hooks before build
 	git.Pipe{},             // get and validate git repo state
 	defaults.Pipe{},        // load default configs
+	snapshot.Pipe{},        // snapshot version handling
 	dist.Pipe{},            // ensure ./dist is clean
 	effectiveconfig.Pipe{}, // writes the actual config (with defaults et al set) to dist
 	changelog.Pipe{},       // builds the release changelog
diff --git a/www/content/snapshots.md b/www/content/snapshots.md
index 8d056e6e..30d9f303 100644
--- a/www/content/snapshots.md
+++ b/www/content/snapshots.md
@@ -7,6 +7,7 @@ weight: 70
 
 Sometimes we want to generate a full build of our project,
 but neither want to validate anything nor upload it to anywhere.
+
 GoReleaser supports this with the `--snapshot` flag
 and also with the `snapshot` customization section:
 
@@ -14,8 +15,12 @@ and also with the `snapshot` customization section:
 # .goreleaser.yml
 snapshot:
   # Allows you to change the name of the generated snapshot
-  # Default is `SNAPSHOT-{{.Commit}}`.
+  # Default is `SNAPSHOT-{{.ShortCommit}}`.
   name_template: SNAPSHOT-{{.Commit}}
 ```
 
 > Learn more about the [name template engine](/templates).
+
+Note that the idea behind GoReleaser's snapshots if mostly for local builds
+or to validate your build on the CI pipeline. Artifacts shouldn't be uploaded
+anywhere, and will only be generated to the `dist` folder.


Test patch:
diff --git a/internal/pipe/git/git_test.go b/internal/pipe/git/git_test.go
index cd67456e..599160ea 100644
--- a/internal/pipe/git/git_test.go
+++ b/internal/pipe/git/git_test.go
@@ -62,37 +62,6 @@ func TestNewRepository(t *testing.T) {
 	assert.Contains(t, Pipe{}.Run(ctx).Error(), `fatal: ambiguous argument 'HEAD'`)
 }
 
-func TestNoTagsSnapshot(t *testing.T) {
-	_, back := testlib.Mktmp(t)
-	defer back()
-	testlib.GitInit(t)
-	testlib.GitRemoteAdd(t, "git@github.com:foo/bar.git")
-	testlib.GitCommit(t, "first")
-	var ctx = context.New(config.Project{
-		Snapshot: config.Snapshot{
-			NameTemplate: "SNAPSHOT-{{.Commit}}",
-		},
-	})
-	ctx.Snapshot = true
-	testlib.AssertSkipped(t, Pipe{}.Run(ctx))
-	assert.Contains(t, ctx.Version, "SNAPSHOT-")
-}
-
-func TestNoTagsSnapshotInvalidTemplate(t *testing.T) {
-	_, back := testlib.Mktmp(t)
-	defer back()
-	testlib.GitInit(t)
-	testlib.GitRemoteAdd(t, "git@github.com:foo/bar.git")
-	testlib.GitCommit(t, "first")
-	var ctx = context.New(config.Project{
-		Snapshot: config.Snapshot{
-			NameTemplate: "{{",
-		},
-	})
-	ctx.Snapshot = true
-	assert.EqualError(t, Pipe{}.Run(ctx), `failed to generate snapshot name: template: tmpl:1: unexpected unclosed action in command`)
-}
-
 // TestNoTagsNoSnapshot covers the situation where a repository
 // only contains simple commits and no tags. In this case you have
 // to set the --snapshot flag otherwise an error is returned.
@@ -224,23 +193,6 @@ func TestSnapshotDirty(t *testing.T) {
 	testlib.AssertSkipped(t, Pipe{}.Run(ctx))
 }
 
-func TestShortCommitHash(t *testing.T) {
-	_, back := testlib.Mktmp(t)
-	defer back()
-	testlib.GitInit(t)
-	testlib.GitRemoteAdd(t, "git@github.com:foo/bar.git")
-	testlib.GitCommit(t, "first")
-	var ctx = context.New(config.Project{
-		Snapshot: config.Snapshot{
-			NameTemplate: "{{.Commit}}",
-		},
-	})
-	ctx.Snapshot = true
-	ctx.Config.Git.ShortHash = true
-	testlib.AssertSkipped(t, Pipe{}.Run(ctx))
-	assert.Len(t, ctx.Version, 7)
-}
-
 func TestGitNotInPath(t *testing.T) {
 	var path = os.Getenv("PATH")
 	defer func() {
diff --git a/internal/pipe/snapshot/snapshot_test.go b/internal/pipe/snapshot/snapshot_test.go
index 1de62bd4..b7f994ee 100644
--- a/internal/pipe/snapshot/snapshot_test.go
+++ b/internal/pipe/snapshot/snapshot_test.go
@@ -3,6 +3,7 @@ package snapshot
 import (
 	"testing"
 
+	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
 	"github.com/stretchr/testify/assert"
@@ -18,7 +19,7 @@ func TestDefault(t *testing.T) {
 		},
 	}
 	assert.NoError(t, Pipe{}.Default(ctx))
-	assert.Equal(t, "SNAPSHOT-{{ .Commit }}", ctx.Config.Snapshot.NameTemplate)
+	assert.Equal(t, "SNAPSHOT-{{ .ShortCommit }}", ctx.Config.Snapshot.NameTemplate)
 }
 
 func TestDefaultSet(t *testing.T) {
@@ -32,3 +33,43 @@ func TestDefaultSet(t *testing.T) {
 	assert.NoError(t, Pipe{}.Default(ctx))
 	assert.Equal(t, "snap", ctx.Config.Snapshot.NameTemplate)
 }
+
+func TestSnapshotNameShortCommitHash(t *testing.T) {
+	var ctx = context.New(config.Project{
+		Snapshot: config.Snapshot{
+			NameTemplate: "{{.ShortCommit}}",
+		},
+	})
+	ctx.Snapshot = true
+	ctx.Config.Git.ShortHash = true
+	ctx.Git.CurrentTag = "v1.2.3"
+	ctx.Git.ShortCommit = "123"
+	assert.NoError(t, Pipe{}.Run(ctx))
+	assert.Equal(t, ctx.Version, "123")
+}
+
+func TestSnapshotInvalidNametemplate(t *testing.T) {
+	var ctx = context.New(config.Project{
+		Snapshot: config.Snapshot{
+			NameTemplate: "{{.ShortCommit}{{{sss}}}",
+		},
+	})
+	ctx.Snapshot = true
+	assert.EqualError(t, Pipe{}.Run(ctx), `failed to generate snapshot name: template: tmpl:1: unexpected "}" in operand`)
+}
+
+func TestSnapshotEmptyFinalName(t *testing.T) {
+	var ctx = context.New(config.Project{
+		Snapshot: config.Snapshot{
+			NameTemplate: "{{ .Commit }}",
+		},
+	})
+	ctx.Snapshot = true
+	ctx.Git.CurrentTag = "v1.2.3"
+	assert.EqualError(t, Pipe{}.Run(ctx), "empty snapshot name")
+}
+
+func TestNotASnapshot(t *testing.T) {
+	var ctx = context.New(config.Project{})
+	testlib.AssertSkipped(t, Pipe{}.Run(ctx))
+}