github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/pipe/snapcraft/snapcraft_test.go (about)

     1  package snapcraft
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/goreleaser/goreleaser/internal/artifact"
    10  	"github.com/goreleaser/goreleaser/internal/gio"
    11  	"github.com/goreleaser/goreleaser/internal/pipe"
    12  	"github.com/goreleaser/goreleaser/internal/testlib"
    13  	"github.com/goreleaser/goreleaser/pkg/config"
    14  	"github.com/goreleaser/goreleaser/pkg/context"
    15  	"github.com/stretchr/testify/require"
    16  	"gopkg.in/yaml.v2"
    17  )
    18  
    19  func TestDescription(t *testing.T) {
    20  	require.NotEmpty(t, Pipe{}.String())
    21  }
    22  
    23  func TestRunPipeMissingInfo(t *testing.T) {
    24  	for eerr, snap := range map[error]config.Snapcraft{
    25  		ErrNoSummary: {
    26  			Description: "dummy desc",
    27  		},
    28  		ErrNoDescription: {
    29  			Summary: "dummy summary",
    30  		},
    31  		pipe.Skip("no summary nor description were provided"): {},
    32  	} {
    33  		t.Run(fmt.Sprintf("testing if %v happens", eerr), func(t *testing.T) {
    34  			ctx := &context.Context{
    35  				Config: config.Project{
    36  					Snapcrafts: []config.Snapcraft{
    37  						snap,
    38  					},
    39  				},
    40  			}
    41  			require.Equal(t, eerr, Pipe{}.Run(ctx))
    42  		})
    43  	}
    44  }
    45  
    46  func TestRunPipe(t *testing.T) {
    47  	folder := t.TempDir()
    48  	dist := filepath.Join(folder, "dist")
    49  	require.NoError(t, os.Mkdir(dist, 0o755))
    50  	ctx := context.New(config.Project{
    51  		ProjectName: "mybin",
    52  		Dist:        dist,
    53  		Snapcrafts: []config.Snapcraft{
    54  			{
    55  				NameTemplate:     "foo_{{.Arch}}",
    56  				Summary:          "test summary",
    57  				Description:      "test description",
    58  				Publish:          true,
    59  				Builds:           []string{"foo"},
    60  				ChannelTemplates: []string{"stable"},
    61  			},
    62  			{
    63  				NameTemplate:     "foo_and_bar_{{.Arch}}",
    64  				Summary:          "test summary",
    65  				Description:      "test description",
    66  				Publish:          true,
    67  				Builds:           []string{"foo", "bar"},
    68  				ChannelTemplates: []string{"stable"},
    69  			},
    70  			{
    71  				NameTemplate:     "bar_{{.Arch}}",
    72  				Summary:          "test summary",
    73  				Description:      "test description",
    74  				Publish:          true,
    75  				Builds:           []string{"bar"},
    76  				ChannelTemplates: []string{"stable"},
    77  			},
    78  		},
    79  	})
    80  	ctx.Git.CurrentTag = "v1.2.3"
    81  	ctx.Version = "v1.2.3"
    82  	addBinaries(t, ctx, "foo", filepath.Join(dist, "foo"))
    83  	addBinaries(t, ctx, "bar", filepath.Join(dist, "bar"))
    84  	require.NoError(t, Pipe{}.Run(ctx))
    85  	list := ctx.Artifacts.Filter(artifact.ByType(artifact.PublishableSnapcraft)).List()
    86  	require.Len(t, list, 9)
    87  }
    88  
    89  func TestRunPipeInvalidNameTemplate(t *testing.T) {
    90  	folder := t.TempDir()
    91  	dist := filepath.Join(folder, "dist")
    92  	require.NoError(t, os.Mkdir(dist, 0o755))
    93  	ctx := context.New(config.Project{
    94  		ProjectName: "foo",
    95  		Dist:        dist,
    96  		Snapcrafts: []config.Snapcraft{
    97  			{
    98  				NameTemplate:     "foo_{{.Arch}",
    99  				Summary:          "test summary",
   100  				Description:      "test description",
   101  				Builds:           []string{"foo"},
   102  				ChannelTemplates: []string{"stable"},
   103  			},
   104  		},
   105  	})
   106  	ctx.Git.CurrentTag = "v1.2.3"
   107  	ctx.Version = "v1.2.3"
   108  	addBinaries(t, ctx, "foo", dist)
   109  	require.EqualError(t, Pipe{}.Run(ctx), `template: tmpl:1: unexpected "}" in operand`)
   110  }
   111  
   112  func TestRunPipeWithName(t *testing.T) {
   113  	folder := t.TempDir()
   114  	dist := filepath.Join(folder, "dist")
   115  	require.NoError(t, os.Mkdir(dist, 0o755))
   116  	ctx := context.New(config.Project{
   117  		ProjectName: "testprojectname",
   118  		Dist:        dist,
   119  		Snapcrafts: []config.Snapcraft{
   120  			{
   121  				NameTemplate:     "foo_{{.Arch}}",
   122  				Name:             "testsnapname",
   123  				Base:             "core18",
   124  				License:          "MIT",
   125  				Summary:          "test summary",
   126  				Description:      "test description",
   127  				Builds:           []string{"foo"},
   128  				ChannelTemplates: []string{"stable"},
   129  			},
   130  		},
   131  	})
   132  	ctx.Git.CurrentTag = "v1.2.3"
   133  	ctx.Version = "v1.2.3"
   134  	addBinaries(t, ctx, "foo", dist)
   135  	require.NoError(t, Pipe{}.Run(ctx))
   136  	yamlFile, err := os.ReadFile(filepath.Join(dist, "foo_amd64", "prime", "meta", "snap.yaml"))
   137  	require.NoError(t, err)
   138  	var metadata Metadata
   139  	err = yaml.Unmarshal(yamlFile, &metadata)
   140  	require.NoError(t, err)
   141  	require.Equal(t, "testsnapname", metadata.Name)
   142  	require.Equal(t, "core18", metadata.Base)
   143  	require.Equal(t, "MIT", metadata.License)
   144  	require.Equal(t, "foo", metadata.Apps["testsnapname"].Command)
   145  }
   146  
   147  func TestRunPipeMetadata(t *testing.T) {
   148  	folder := t.TempDir()
   149  	dist := filepath.Join(folder, "dist")
   150  	require.NoError(t, os.Mkdir(dist, 0o755))
   151  	ctx := context.New(config.Project{
   152  		ProjectName: "testprojectname",
   153  		Dist:        dist,
   154  		Snapcrafts: []config.Snapcraft{
   155  			{
   156  				Name:         "testprojectname",
   157  				NameTemplate: "foo_{{.Arch}}",
   158  				Summary:      "test summary",
   159  				Description:  "test description",
   160  				Layout: map[string]config.SnapcraftLayoutMetadata{
   161  					"/etc/testprojectname": {Bind: "$SNAP_DATA/etc"},
   162  				},
   163  				Apps: map[string]config.SnapcraftAppMetadata{
   164  					"foo": {
   165  						Plugs:            []string{"home", "network", "personal-files"},
   166  						Daemon:           "simple",
   167  						Args:             "--foo --bar",
   168  						RestartCondition: "always",
   169  					},
   170  				},
   171  				Plugs: map[string]interface{}{
   172  					"personal-files": map[string]interface{}{
   173  						"read": []string{"$HOME/test"},
   174  					},
   175  				},
   176  				Builds:           []string{"foo"},
   177  				ChannelTemplates: []string{"stable"},
   178  			},
   179  		},
   180  	})
   181  	ctx.Git.CurrentTag = "v1.2.3"
   182  	ctx.Version = "v1.2.3"
   183  	addBinaries(t, ctx, "foo", dist)
   184  	require.NoError(t, Pipe{}.Run(ctx))
   185  	yamlFile, err := os.ReadFile(filepath.Join(dist, "foo_amd64", "prime", "meta", "snap.yaml"))
   186  	require.NoError(t, err)
   187  	var metadata Metadata
   188  	err = yaml.Unmarshal(yamlFile, &metadata)
   189  	require.NoError(t, err)
   190  	require.Equal(t, []string{"home", "network", "personal-files"}, metadata.Apps["foo"].Plugs)
   191  	require.Equal(t, "simple", metadata.Apps["foo"].Daemon)
   192  	require.Equal(t, "foo --foo --bar", metadata.Apps["foo"].Command)
   193  	require.Equal(t, []string{"home", "network", "personal-files"}, metadata.Apps["foo"].Plugs)
   194  	require.Equal(t, "simple", metadata.Apps["foo"].Daemon)
   195  	require.Equal(t, "foo --foo --bar", metadata.Apps["foo"].Command)
   196  	require.Equal(t, map[interface{}]interface{}{"read": []interface{}{"$HOME/test"}}, metadata.Plugs["personal-files"])
   197  	require.Equal(t, "always", metadata.Apps["foo"].RestartCondition)
   198  	require.Equal(t, "$SNAP_DATA/etc", metadata.Layout["/etc/testprojectname"].Bind)
   199  }
   200  
   201  func TestNoSnapcraftInPath(t *testing.T) {
   202  	path := os.Getenv("PATH")
   203  	defer func() {
   204  		require.NoError(t, os.Setenv("PATH", path))
   205  	}()
   206  	require.NoError(t, os.Setenv("PATH", ""))
   207  	ctx := context.New(config.Project{
   208  		Snapcrafts: []config.Snapcraft{
   209  			{
   210  				Summary:     "dummy",
   211  				Description: "dummy",
   212  			},
   213  		},
   214  	})
   215  	require.EqualError(t, Pipe{}.Run(ctx), ErrNoSnapcraft.Error())
   216  }
   217  
   218  func TestRunNoArguments(t *testing.T) {
   219  	folder := t.TempDir()
   220  	dist := filepath.Join(folder, "dist")
   221  	require.NoError(t, os.Mkdir(dist, 0o755))
   222  	ctx := context.New(config.Project{
   223  		ProjectName: "testprojectname",
   224  		Dist:        dist,
   225  		Snapcrafts: []config.Snapcraft{
   226  			{
   227  				NameTemplate: "foo_{{.Arch}}",
   228  				Summary:      "test summary",
   229  				Description:  "test description",
   230  				Apps: map[string]config.SnapcraftAppMetadata{
   231  					"foo": {
   232  						Daemon: "simple",
   233  						Args:   "",
   234  					},
   235  				},
   236  				Builds:           []string{"foo"},
   237  				ChannelTemplates: []string{"stable"},
   238  			},
   239  		},
   240  	})
   241  	ctx.Git.CurrentTag = "v1.2.3"
   242  	ctx.Version = "v1.2.3"
   243  	addBinaries(t, ctx, "foo", dist)
   244  	require.NoError(t, Pipe{}.Run(ctx))
   245  	yamlFile, err := os.ReadFile(filepath.Join(dist, "foo_amd64", "prime", "meta", "snap.yaml"))
   246  	require.NoError(t, err)
   247  	var metadata Metadata
   248  	err = yaml.Unmarshal(yamlFile, &metadata)
   249  	require.NoError(t, err)
   250  	require.Equal(t, "foo", metadata.Apps["foo"].Command)
   251  }
   252  
   253  func TestCompleter(t *testing.T) {
   254  	folder := t.TempDir()
   255  	dist := filepath.Join(folder, "dist")
   256  	require.NoError(t, os.Mkdir(dist, 0o755))
   257  	ctx := context.New(config.Project{
   258  		ProjectName: "testprojectname",
   259  		Dist:        dist,
   260  		Snapcrafts: []config.Snapcraft{
   261  			{
   262  				NameTemplate: "foo_{{.Arch}}",
   263  				Summary:      "test summary",
   264  				Description:  "test description",
   265  				Apps: map[string]config.SnapcraftAppMetadata{
   266  					"foo": {
   267  						Daemon:    "simple",
   268  						Args:      "",
   269  						Completer: "testdata/foo-completer.bash",
   270  					},
   271  				},
   272  				Builds:           []string{"foo", "bar"},
   273  				ChannelTemplates: []string{"stable"},
   274  			},
   275  		},
   276  	})
   277  	ctx.Git.CurrentTag = "v1.2.3"
   278  	ctx.Version = "v1.2.3"
   279  	addBinaries(t, ctx, "foo", dist)
   280  	addBinaries(t, ctx, "bar", dist)
   281  	require.NoError(t, Pipe{}.Run(ctx))
   282  	yamlFile, err := os.ReadFile(filepath.Join(dist, "foo_amd64", "prime", "meta", "snap.yaml"))
   283  	require.NoError(t, err)
   284  	var metadata Metadata
   285  	err = yaml.Unmarshal(yamlFile, &metadata)
   286  	require.NoError(t, err)
   287  	require.Equal(t, "foo", metadata.Apps["foo"].Command)
   288  	require.Equal(t, "testdata/foo-completer.bash", metadata.Apps["foo"].Completer)
   289  }
   290  
   291  func TestCommand(t *testing.T) {
   292  	folder := t.TempDir()
   293  	dist := filepath.Join(folder, "dist")
   294  	require.NoError(t, os.Mkdir(dist, 0o755))
   295  	ctx := context.New(config.Project{
   296  		ProjectName: "testprojectname",
   297  		Dist:        dist,
   298  		Snapcrafts: []config.Snapcraft{
   299  			{
   300  				NameTemplate: "foo_{{.Arch}}",
   301  				Summary:      "test summary",
   302  				Description:  "test description",
   303  				Apps: map[string]config.SnapcraftAppMetadata{
   304  					"foo": {
   305  						Daemon:  "simple",
   306  						Args:    "--bar custom command",
   307  						Command: "foo",
   308  					},
   309  				},
   310  				Builds:           []string{"foo"},
   311  				ChannelTemplates: []string{"stable"},
   312  			},
   313  		},
   314  	})
   315  	ctx.Git.CurrentTag = "v1.2.3"
   316  	ctx.Version = "v1.2.3"
   317  	addBinaries(t, ctx, "foo", dist)
   318  	require.NoError(t, Pipe{}.Run(ctx))
   319  	yamlFile, err := os.ReadFile(filepath.Join(dist, "foo_amd64", "prime", "meta", "snap.yaml"))
   320  	require.NoError(t, err)
   321  	var metadata Metadata
   322  	err = yaml.Unmarshal(yamlFile, &metadata)
   323  	require.NoError(t, err)
   324  	require.Equal(t, "foo --bar custom command", metadata.Apps["foo"].Command)
   325  }
   326  
   327  func TestExtraFile(t *testing.T) {
   328  	folder := t.TempDir()
   329  	dist := filepath.Join(folder, "dist")
   330  	require.NoError(t, os.Mkdir(dist, 0o755))
   331  	ctx := context.New(config.Project{
   332  		ProjectName: "testprojectname",
   333  		Dist:        dist,
   334  		Snapcrafts: []config.Snapcraft{
   335  			{
   336  				NameTemplate: "foo_{{.Arch}}",
   337  				Summary:      "test summary",
   338  				Description:  "test description",
   339  				Files: []config.SnapcraftExtraFiles{
   340  					{
   341  						Source:      "testdata/extra-file.txt",
   342  						Destination: "a/b/c/extra-file.txt",
   343  						Mode:        0o755,
   344  					},
   345  					{
   346  						Source: "testdata/extra-file-2.txt",
   347  					},
   348  				},
   349  				Builds:           []string{"foo"},
   350  				ChannelTemplates: []string{"stable"},
   351  			},
   352  		},
   353  	})
   354  	ctx.Git.CurrentTag = "v1.2.3"
   355  	ctx.Version = "v1.2.3"
   356  	addBinaries(t, ctx, "foo", dist)
   357  	require.NoError(t, Pipe{}.Run(ctx))
   358  
   359  	requireEqualFiles(t, "testdata/extra-file.txt", filepath.Join(dist, "foo_amd64", "prime", "a", "b", "c", "extra-file.txt"))
   360  	requireEqualFiles(t, "testdata/extra-file-2.txt", filepath.Join(dist, "foo_amd64", "prime", "testdata", "extra-file-2.txt"))
   361  }
   362  
   363  func TestDefault(t *testing.T) {
   364  	ctx := context.New(config.Project{
   365  		Builds: []config.Build{
   366  			{
   367  				ID: "foo",
   368  			},
   369  		},
   370  		Snapcrafts: []config.Snapcraft{
   371  			{},
   372  		},
   373  	})
   374  	require.NoError(t, Pipe{}.Default(ctx))
   375  	require.Equal(t, defaultNameTemplate, ctx.Config.Snapcrafts[0].NameTemplate)
   376  	require.Equal(t, []string{"foo"}, ctx.Config.Snapcrafts[0].Builds)
   377  }
   378  
   379  func TestPublish(t *testing.T) {
   380  	ctx := context.New(config.Project{})
   381  	ctx.Artifacts.Add(&artifact.Artifact{
   382  		Name:   "mybin",
   383  		Path:   "nope.snap",
   384  		Goarch: "amd64",
   385  		Goos:   "linux",
   386  		Type:   artifact.PublishableSnapcraft,
   387  		Extra: map[string]interface{}{
   388  			releasesExtra: []string{"stable", "candidate"},
   389  		},
   390  	})
   391  	err := Pipe{}.Publish(ctx)
   392  	require.Contains(t, err.Error(), "failed to push nope.snap package")
   393  }
   394  
   395  func TestPublishSkip(t *testing.T) {
   396  	ctx := context.New(config.Project{})
   397  	ctx.SkipPublish = true
   398  	ctx.Artifacts.Add(&artifact.Artifact{
   399  		Name:   "mybin",
   400  		Path:   "nope.snap",
   401  		Goarch: "amd64",
   402  		Goos:   "linux",
   403  		Type:   artifact.PublishableSnapcraft,
   404  		Extra: map[string]interface{}{
   405  			releasesExtra: []string{"stable"},
   406  		},
   407  	})
   408  	testlib.AssertSkipped(t, Pipe{}.Publish(ctx))
   409  }
   410  
   411  func TestDefaultSet(t *testing.T) {
   412  	ctx := context.New(config.Project{
   413  		Snapcrafts: []config.Snapcraft{
   414  			{
   415  				ID:           "devel",
   416  				NameTemplate: "foo",
   417  				Grade:        "devel",
   418  			},
   419  			{
   420  				ID:           "stable",
   421  				NameTemplate: "bar",
   422  				Grade:        "stable",
   423  			},
   424  		},
   425  	})
   426  	require.NoError(t, Pipe{}.Default(ctx))
   427  	require.Equal(t, "foo", ctx.Config.Snapcrafts[0].NameTemplate)
   428  	require.Equal(t, []string{"edge", "beta"}, ctx.Config.Snapcrafts[0].ChannelTemplates)
   429  	require.Equal(t, []string{"edge", "beta", "candidate", "stable"}, ctx.Config.Snapcrafts[1].ChannelTemplates)
   430  }
   431  
   432  func Test_processChannelsTemplates(t *testing.T) {
   433  	ctx := &context.Context{
   434  		Config: config.Project{
   435  			Builds: []config.Build{
   436  				{
   437  					ID: "default",
   438  				},
   439  			},
   440  			Snapcrafts: []config.Snapcraft{
   441  				{
   442  					Name: "mybin",
   443  					ChannelTemplates: []string{
   444  						"{{.Major}}.{{.Minor}}/stable",
   445  						"stable",
   446  					},
   447  				},
   448  			},
   449  		},
   450  	}
   451  
   452  	ctx.SkipPublish = true
   453  	ctx.Env = map[string]string{
   454  		"FOO": "123",
   455  	}
   456  	ctx.Version = "1.0.0"
   457  	ctx.Git = context.GitInfo{
   458  		CurrentTag: "v1.0.0",
   459  		Commit:     "a1b2c3d4",
   460  	}
   461  	ctx.Semver = context.Semver{
   462  		Major: 1,
   463  		Minor: 0,
   464  		Patch: 0,
   465  	}
   466  
   467  	require.NoError(t, Pipe{}.Default(ctx))
   468  
   469  	snap := ctx.Config.Snapcrafts[0]
   470  	require.Equal(t, "mybin", snap.Name)
   471  
   472  	channels, err := processChannelsTemplates(ctx, snap)
   473  	require.NoError(t, err)
   474  	require.Equal(t, []string{
   475  		"1.0/stable",
   476  		"stable",
   477  	}, channels)
   478  }
   479  
   480  func addBinaries(t *testing.T, ctx *context.Context, name, dist string) {
   481  	t.Helper()
   482  	for _, goos := range []string{"linux", "darwin"} {
   483  		for _, goarch := range []string{"amd64", "386", "arm6"} {
   484  			folder := goos + goarch
   485  			require.NoError(t, os.MkdirAll(filepath.Join(dist, folder), 0o755))
   486  			binPath := filepath.Join(dist, folder, name)
   487  			f, err := os.Create(binPath)
   488  			require.NoError(t, err)
   489  			require.NoError(t, f.Close())
   490  			ctx.Artifacts.Add(&artifact.Artifact{
   491  				Name:   "subdir/" + name,
   492  				Path:   binPath,
   493  				Goarch: goarch,
   494  				Goos:   goos,
   495  				Type:   artifact.Binary,
   496  				Extra: map[string]interface{}{
   497  					"ID": name,
   498  				},
   499  			})
   500  		}
   501  	}
   502  }
   503  
   504  func TestSeveralSnapssWithTheSameID(t *testing.T) {
   505  	ctx := &context.Context{
   506  		Config: config.Project{
   507  			Snapcrafts: []config.Snapcraft{
   508  				{
   509  					ID: "a",
   510  				},
   511  				{
   512  					ID: "a",
   513  				},
   514  			},
   515  		},
   516  	}
   517  	require.EqualError(t, Pipe{}.Default(ctx), "found 2 snapcrafts with the ID 'a', please fix your config")
   518  }
   519  
   520  func Test_isValidArch(t *testing.T) {
   521  	tests := []struct {
   522  		arch string
   523  		want bool
   524  	}{
   525  		{"s390x", true},
   526  		{"ppc64el", true},
   527  		{"arm64", true},
   528  		{"armhf", true},
   529  		{"amd64", true},
   530  		{"i386", true},
   531  		{"mips", false},
   532  		{"armel", false},
   533  	}
   534  	for _, tt := range tests {
   535  		t.Run(tt.arch, func(t *testing.T) {
   536  			require.Equal(t, tt.want, isValidArch(tt.arch))
   537  		})
   538  	}
   539  }
   540  
   541  func TestSkip(t *testing.T) {
   542  	t.Run("skip", func(t *testing.T) {
   543  		require.True(t, Pipe{}.Skip(context.New(config.Project{})))
   544  	})
   545  
   546  	t.Run("dont skip", func(t *testing.T) {
   547  		ctx := context.New(config.Project{
   548  			Snapcrafts: []config.Snapcraft{
   549  				{},
   550  			},
   551  		})
   552  		require.False(t, Pipe{}.Skip(ctx))
   553  	})
   554  }
   555  
   556  func requireEqualFiles(tb testing.TB, a, b string) {
   557  	tb.Helper()
   558  	eq, err := gio.EqualFiles(a, b)
   559  	require.NoError(tb, err)
   560  	require.True(tb, eq, "%s != %s", a, b)
   561  }