mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-06 03:13:48 +02:00
99afc8d62e
very, very, very WIP implementation of nixpkgs for GoReleaser. **Decisions made for this first version:** - only linux and darwin, arm64, 386 and amd64 - only support pkgs from goreleaser-generated archives - no support to push into default nixpkgs repository - no support to automatically add the _maybe_ new pkg to the root `default.nix` - the generated nixpkg will be rather verbose, which shouldn't be too much of an issue as it is autogenerated anyway **TODOs**: - [x] macos universal binary support - [x] custom pkg path (e.g. pkgs/misc/foo/bar/default.nix) - [x] handle archives with a folder in them - [x] add more options: postInstall, ?? **Will be handled in future versions**: - [ ] archives.format=binary support - [ ] compile from source - [ ] PR-ing into nixpkgs - [ ] armv6l-linux & armv7l-linux support closes #3537 --------- Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
408 lines
10 KiB
Go
408 lines
10 KiB
Go
package nix
|
|
|
|
import (
|
|
"html/template"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/goreleaser/goreleaser/internal/artifact"
|
|
"github.com/goreleaser/goreleaser/internal/client"
|
|
"github.com/goreleaser/goreleaser/internal/golden"
|
|
"github.com/goreleaser/goreleaser/internal/testctx"
|
|
"github.com/goreleaser/goreleaser/pkg/config"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestString(t *testing.T) {
|
|
require.NotEmpty(t, Pipe{}.String())
|
|
}
|
|
|
|
func TestSkip(t *testing.T) {
|
|
t.Run("no-nix", func(t *testing.T) {
|
|
require.True(t, Pipe{}.Skip(testctx.New()))
|
|
})
|
|
t.Run("nix-all-good", func(t *testing.T) {
|
|
require.False(t, NewPublish().Skip(testctx.NewWithCfg(config.Project{
|
|
Nix: []config.Nix{{}},
|
|
})))
|
|
})
|
|
t.Run("prefetcher-not-in-path", func(t *testing.T) {
|
|
t.Setenv("PATH", "nope")
|
|
require.True(t, NewPublish().Skip(testctx.NewWithCfg(config.Project{
|
|
Nix: []config.Nix{{}},
|
|
})))
|
|
})
|
|
}
|
|
|
|
const fakeNixPrefetchURLBin = "fake-nix-prefetch-url"
|
|
|
|
func TestPrefetcher(t *testing.T) {
|
|
t.Run("prefetch", func(t *testing.T) {
|
|
t.Run("build", func(t *testing.T) {
|
|
sha, err := buildShaPrefetcher{}.Prefetch("any")
|
|
require.NoError(t, err)
|
|
require.Equal(t, zeroHash, sha)
|
|
})
|
|
t.Run("publish", func(t *testing.T) {
|
|
t.Run("no-nix-prefetch-url", func(t *testing.T) {
|
|
_, err := publishShaPrefetcher{fakeNixPrefetchURLBin}.Prefetch("any")
|
|
require.ErrorIs(t, err, exec.ErrNotFound)
|
|
})
|
|
t.Run("valid", func(t *testing.T) {
|
|
sha, err := publishShaPrefetcher{nixPrefetchURLBin}.Prefetch("https://github.com/goreleaser/goreleaser/releases/download/v1.18.2/goreleaser_Darwin_arm64.tar.gz")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "0girjxp07srylyq36xk1ska8p68m2fhp05xgyv4wkcl61d6rzv3y", sha)
|
|
})
|
|
})
|
|
})
|
|
t.Run("available", func(t *testing.T) {
|
|
t.Run("build", func(t *testing.T) {
|
|
require.True(t, buildShaPrefetcher{}.Available())
|
|
})
|
|
t.Run("publish", func(t *testing.T) {
|
|
t.Run("no-nix-prefetch-url", func(t *testing.T) {
|
|
require.False(t, publishShaPrefetcher{fakeNixPrefetchURLBin}.Available())
|
|
})
|
|
t.Run("valid", func(t *testing.T) {
|
|
require.True(t, publishShaPrefetcher{nixPrefetchURLBin}.Available())
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRunPipe(t *testing.T) {
|
|
for _, tt := range []struct {
|
|
name string
|
|
expectRunErrorIs error
|
|
expectPublishErrorIs error
|
|
nix config.Nix
|
|
}{
|
|
{
|
|
name: "minimal",
|
|
nix: config.Nix{
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "open-pr",
|
|
nix: config.Nix{
|
|
Name: "foo",
|
|
IDs: []string{"foo"},
|
|
Description: "my test",
|
|
Homepage: "https://goreleaser.com",
|
|
License: "mit",
|
|
Path: "pkgs/foo.nix",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
Branch: "update-{{.Version}}",
|
|
PullRequest: config.PullRequest{
|
|
Enabled: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "wrapped-in-dir",
|
|
nix: config.Nix{
|
|
Name: "wrapped-in-dir",
|
|
IDs: []string{"wrapped-in-dir"},
|
|
Description: "my test",
|
|
Homepage: "https://goreleaser.com",
|
|
License: "mit",
|
|
PostInstall: `
|
|
echo "do something"
|
|
`,
|
|
Install: `
|
|
mkdir -p $out/bin
|
|
cp foo $out/bin/foo
|
|
`,
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "unibin",
|
|
nix: config.Nix{
|
|
Name: "unibin",
|
|
IDs: []string{"unibin"},
|
|
Description: "my test",
|
|
Homepage: "https://goreleaser.com",
|
|
License: "mit",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "no-archives",
|
|
expectRunErrorIs: errNoArchivesFound{
|
|
goamd64: "v2",
|
|
ids: []string{"nopenopenope"},
|
|
},
|
|
nix: config.Nix{
|
|
Name: "no-archives",
|
|
IDs: []string{"nopenopenope"},
|
|
Goamd64: "v2",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "unibin-replaces",
|
|
nix: config.Nix{
|
|
Name: "unibin-replaces",
|
|
IDs: []string{"unibin-replaces"},
|
|
Description: "my test",
|
|
Homepage: "https://goreleaser.com",
|
|
License: "mit",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "partial",
|
|
nix: config.Nix{
|
|
Name: "partial",
|
|
IDs: []string{"partial"},
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "no-repo-name",
|
|
expectRunErrorIs: errNoRepoName,
|
|
nix: config.Nix{
|
|
Name: "doesnotmatter",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "bad-name-tmpl",
|
|
expectRunErrorIs: &template.Error{},
|
|
nix: config.Nix{
|
|
Name: "{{ .Nope }}",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "bad-repo-tmpl",
|
|
expectRunErrorIs: &template.Error{},
|
|
nix: config.Nix{
|
|
Name: "doesnotmatter",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "{{ .Nope }}",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "bad-skip-upload-tmpl",
|
|
expectRunErrorIs: &template.Error{},
|
|
nix: config.Nix{
|
|
Name: "doesnotmatter",
|
|
SkipUpload: "{{ .Nope }}",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "bad-install-tmpl",
|
|
expectRunErrorIs: &template.Error{},
|
|
nix: config.Nix{
|
|
Name: "foo",
|
|
Install: `{{.NoInstall}}`,
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "bad-post-install-tmpl",
|
|
expectRunErrorIs: &template.Error{},
|
|
nix: config.Nix{
|
|
Name: "foo",
|
|
PostInstall: `{{.NoPostInstall}}`,
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "bad-release-url-tmpl",
|
|
expectRunErrorIs: &template.Error{},
|
|
nix: config.Nix{
|
|
Name: "foo",
|
|
URLTemplate: "{{.BadURL}}",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "skip-upload",
|
|
expectPublishErrorIs: errSkipUpload,
|
|
nix: config.Nix{
|
|
Name: "doesnotmatter",
|
|
SkipUpload: "true",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "skip-upload-auto",
|
|
expectPublishErrorIs: errSkipUploadAuto,
|
|
nix: config.Nix{
|
|
Name: "doesnotmatter",
|
|
SkipUpload: "auto",
|
|
Repository: config.RepoRef{
|
|
Owner: "foo",
|
|
Name: "bar",
|
|
},
|
|
},
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
folder := t.TempDir()
|
|
ctx := testctx.NewWithCfg(
|
|
config.Project{
|
|
Dist: folder,
|
|
ProjectName: "foo",
|
|
Nix: []config.Nix{tt.nix},
|
|
},
|
|
testctx.WithVersion("1.2.1"),
|
|
testctx.WithCurrentTag("v1.2.1"),
|
|
testctx.WithSemver(1, 2, 1, "rc1"),
|
|
)
|
|
createFakeArtifact := func(id, goos, goarch string, extra map[string]any) {
|
|
path := filepath.Join(folder, "dist/foo_"+goos+goarch+".tar.gz")
|
|
art := artifact.Artifact{
|
|
Name: "foo_" + goos + "_" + goarch + ".tar.gz",
|
|
Path: path,
|
|
Goos: goos,
|
|
Goarch: goarch,
|
|
Goamd64: "v1",
|
|
Type: artifact.UploadableArchive,
|
|
Extra: map[string]interface{}{
|
|
artifact.ExtraID: id,
|
|
artifact.ExtraFormat: "tar.gz",
|
|
artifact.ExtraBinaries: []string{"foo"},
|
|
artifact.ExtraWrappedIn: "",
|
|
},
|
|
}
|
|
for k, v := range extra {
|
|
art.Extra[k] = v
|
|
}
|
|
ctx.Artifacts.Add(&art)
|
|
|
|
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755))
|
|
f, err := os.Create(path)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.Close())
|
|
}
|
|
|
|
createFakeArtifact("unibin-replaces", "darwin", "all", map[string]any{artifact.ExtraReplaces: true})
|
|
createFakeArtifact("unibin", "darwin", "all", nil)
|
|
for _, goos := range []string{"linux", "darwin", "windows"} {
|
|
for _, goarch := range []string{"amd64", "arm64", "386"} {
|
|
if goos+goarch == "darwin386" {
|
|
continue
|
|
}
|
|
if goarch == "amd64" {
|
|
createFakeArtifact("partial", goos, goarch, nil)
|
|
}
|
|
createFakeArtifact("foo", goos, goarch, nil)
|
|
createFakeArtifact("unibin", goos, goarch, nil)
|
|
createFakeArtifact("unibin-replaces", goos, goarch, nil)
|
|
createFakeArtifact("wrapped-in-dir", goos, goarch, map[string]any{artifact.ExtraWrappedIn: "./foo"})
|
|
}
|
|
}
|
|
|
|
client := client.NewMock()
|
|
bpipe := NewBuild()
|
|
ppipe := Pipe{
|
|
fakeNixShaPrefetcher{
|
|
"https://dummyhost/download/v1.2.1/foo_linux_amd64.tar.gz": "sha1",
|
|
"https://dummyhost/download/v1.2.1/foo_linux_arm64.tar.gz": "sha2",
|
|
"https://dummyhost/download/v1.2.1/foo_darwin_amd64.tar.gz": "sha3",
|
|
"https://dummyhost/download/v1.2.1/foo_darwin_arm64.tar.gz": "sha4",
|
|
"https://dummyhost/download/v1.2.1/foo_darwin_all.tar.gz": "sha5",
|
|
},
|
|
}
|
|
|
|
// default
|
|
require.NoError(t, bpipe.Default(ctx))
|
|
|
|
// run
|
|
if tt.expectRunErrorIs != nil {
|
|
err := bpipe.runAll(ctx, client)
|
|
require.ErrorAs(t, err, &tt.expectPublishErrorIs)
|
|
return
|
|
}
|
|
require.NoError(t, bpipe.runAll(ctx, client))
|
|
bts, err := os.ReadFile(ctx.Artifacts.Filter(artifact.ByType(artifact.Nixpkg)).Paths()[0])
|
|
require.NoError(t, err)
|
|
golden.RequireEqualExt(t, bts, "_build.nix")
|
|
|
|
// publish
|
|
if tt.expectPublishErrorIs != nil {
|
|
err := ppipe.publishAll(ctx, client)
|
|
require.ErrorAs(t, err, &tt.expectPublishErrorIs)
|
|
return
|
|
}
|
|
require.NoError(t, ppipe.publishAll(ctx, client))
|
|
require.True(t, client.CreatedFile)
|
|
golden.RequireEqualExt(t, []byte(client.Content), "_publish.nix")
|
|
require.NotContains(t, client.Content, strings.Repeat("0", 52))
|
|
|
|
if tt.nix.Repository.PullRequest.Enabled {
|
|
require.True(t, client.OpenedPullRequest)
|
|
}
|
|
if tt.nix.Path != "" {
|
|
require.Equal(t, tt.nix.Path, client.Path)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestErrNoArchivesFound(t *testing.T) {
|
|
require.EqualError(t, errNoArchivesFound{
|
|
goamd64: "v1",
|
|
ids: []string{"foo", "bar"},
|
|
}, "no linux/macos archives found matching goos=[darwin linux] goarch=[amd64 arm64 386] goamd64=v1 ids=[foo bar]")
|
|
}
|
|
|
|
type fakeNixShaPrefetcher map[string]string
|
|
|
|
func (m fakeNixShaPrefetcher) Prefetch(url string) (string, error) {
|
|
return m[url], nil
|
|
}
|
|
func (m fakeNixShaPrefetcher) Available() bool { return true }
|