github.com/goreleaser/goreleaser@v1.25.1/internal/exec/exec_test.go (about)

     1  package exec
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/goreleaser/goreleaser/internal/artifact"
    11  	"github.com/goreleaser/goreleaser/internal/pipe"
    12  	"github.com/goreleaser/goreleaser/internal/testctx"
    13  	"github.com/goreleaser/goreleaser/internal/tmpl"
    14  	"github.com/goreleaser/goreleaser/pkg/config"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestExecute(t *testing.T) {
    19  	ctx := testctx.NewWithCfg(config.Project{
    20  		ProjectName: "blah",
    21  		Env: []string{
    22  			"TEST_A_SECRET=x",
    23  			"TEST_A_USERNAME=u2",
    24  		},
    25  	}, testctx.WithVersion("2.1.0"))
    26  
    27  	// Preload artifacts
    28  	folder := t.TempDir()
    29  	for _, a := range []struct {
    30  		id  string
    31  		ext string
    32  		typ artifact.Type
    33  	}{
    34  		{"debpkg", "deb", artifact.LinuxPackage},
    35  		{"binary", "bin", artifact.Binary},
    36  		{"archive", "tar", artifact.UploadableArchive},
    37  		{"ubinary", "ubi", artifact.UploadableBinary},
    38  		{"checksum", "sum", artifact.Checksum},
    39  		{"metadata", "json", artifact.Metadata},
    40  		{"signature", "sig", artifact.Signature},
    41  		{"signature", "pem", artifact.Certificate},
    42  	} {
    43  		file := filepath.Join(folder, "a."+a.ext)
    44  		require.NoError(t, os.WriteFile(file, []byte("lorem ipsum"), 0o644))
    45  		ctx.Artifacts.Add(&artifact.Artifact{
    46  			Name:   "a." + a.ext,
    47  			Goos:   "linux",
    48  			Goarch: "amd64",
    49  			Path:   file,
    50  			Type:   a.typ,
    51  			Extra: map[string]interface{}{
    52  				artifact.ExtraID: a.id,
    53  			},
    54  		})
    55  	}
    56  
    57  	ctx.Artifacts.Add(&artifact.Artifact{
    58  		Name:   "foo/bar:amd64",
    59  		Goos:   "linux",
    60  		Goarch: "amd64",
    61  		Path:   "foo/bar:amd64",
    62  		Type:   artifact.DockerImage,
    63  		Extra: map[string]interface{}{
    64  			artifact.ExtraID: "img",
    65  		},
    66  	})
    67  	ctx.Artifacts.Add(&artifact.Artifact{
    68  		Name: "foo/bar",
    69  		Path: "foo/bar",
    70  		Type: artifact.DockerManifest,
    71  		Extra: map[string]interface{}{
    72  			artifact.ExtraID: "mnf",
    73  		},
    74  	})
    75  
    76  	osEnv := func(ignores ...string) []string {
    77  		var result []string
    78  	outer:
    79  		for _, key := range passthroughEnvVars {
    80  			for _, ignore := range ignores {
    81  				if key == ignore {
    82  					continue outer
    83  				}
    84  			}
    85  			if value := os.Getenv(key); value != "" {
    86  				result = append(result, key+"="+value)
    87  			}
    88  		}
    89  		return result
    90  	}
    91  
    92  	testCases := []struct {
    93  		name        string
    94  		publishers  []config.Publisher
    95  		expectErr   error
    96  		expectErrAs any
    97  	}{
    98  		{
    99  			"filter by IDs",
   100  			[]config.Publisher{
   101  				{
   102  					Name: "test",
   103  					IDs:  []string{"archive"},
   104  					Cmd:  MockCmd + " {{ .ArtifactName }}",
   105  					Env: []string{
   106  						MarshalMockEnv(&MockData{
   107  							AnyOf: []MockCall{
   108  								{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   109  							},
   110  						}),
   111  					},
   112  				},
   113  			},
   114  			nil,
   115  			nil,
   116  		},
   117  		{
   118  			"no filter",
   119  			[]config.Publisher{
   120  				{
   121  					Name:    "test",
   122  					Cmd:     MockCmd + " {{ .ArtifactName }}",
   123  					Disable: "false",
   124  					Env: []string{
   125  						MarshalMockEnv(&MockData{
   126  							AnyOf: []MockCall{
   127  								{ExpectedArgs: []string{"a.deb"}, ExitCode: 0, ExpectedEnv: osEnv()},
   128  								{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
   129  								{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   130  								{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   131  								{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
   132  							},
   133  						}),
   134  					},
   135  				},
   136  			},
   137  			nil,
   138  			nil,
   139  		},
   140  		{
   141  			"disabled",
   142  			[]config.Publisher{
   143  				{
   144  					Name:    "test",
   145  					Cmd:     MockCmd + " {{ .ArtifactName }}",
   146  					Disable: "true",
   147  					Env:     []string{},
   148  				},
   149  			},
   150  			pipe.ErrSkip{},
   151  			nil,
   152  		},
   153  		{
   154  			"disabled invalid tmpl",
   155  			[]config.Publisher{
   156  				{
   157  					Name:    "test",
   158  					Cmd:     MockCmd + " {{ .ArtifactName }}",
   159  					Disable: "{{ .NOPE }}",
   160  					Env:     []string{},
   161  				},
   162  			},
   163  			nil,
   164  			&tmpl.Error{},
   165  		},
   166  		{
   167  			"include checksum",
   168  			[]config.Publisher{
   169  				{
   170  					Name:     "test",
   171  					Checksum: true,
   172  					Cmd:      MockCmd + " {{ .ArtifactName }}",
   173  					Env: []string{
   174  						MarshalMockEnv(&MockData{
   175  							AnyOf: []MockCall{
   176  								{ExpectedArgs: []string{"a.deb"}, ExitCode: 0, ExpectedEnv: osEnv()},
   177  								{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
   178  								{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   179  								{ExpectedArgs: []string{"a.sum"}, ExitCode: 0, ExpectedEnv: osEnv()},
   180  								{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   181  								{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
   182  							},
   183  						}),
   184  					},
   185  				},
   186  			},
   187  			nil,
   188  			nil,
   189  		},
   190  		{
   191  			"include metadata",
   192  			[]config.Publisher{
   193  				{
   194  					Name: "test",
   195  					Meta: true,
   196  					Cmd:  MockCmd + " {{ .ArtifactName }}",
   197  					Env: []string{
   198  						MarshalMockEnv(&MockData{
   199  							AnyOf: []MockCall{
   200  								{ExpectedArgs: []string{"a.deb"}, ExitCode: 0, ExpectedEnv: osEnv()},
   201  								{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
   202  								{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   203  								{ExpectedArgs: []string{"a.json"}, ExitCode: 0, ExpectedEnv: osEnv()},
   204  								{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   205  								{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
   206  							},
   207  						}),
   208  					},
   209  				},
   210  			},
   211  			nil,
   212  			nil,
   213  		},
   214  		{
   215  			"include signatures",
   216  			[]config.Publisher{
   217  				{
   218  					Name:      "test",
   219  					Signature: true,
   220  					Cmd:       MockCmd + " {{ .ArtifactName }}",
   221  					Env: []string{
   222  						MarshalMockEnv(&MockData{
   223  							AnyOf: []MockCall{
   224  								{ExpectedArgs: []string{"a.deb"}, ExitCode: 0, ExpectedEnv: osEnv()},
   225  								{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
   226  								{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   227  								{ExpectedArgs: []string{"a.sig"}, ExitCode: 0, ExpectedEnv: osEnv()},
   228  								{ExpectedArgs: []string{"a.pem"}, ExitCode: 0, ExpectedEnv: osEnv()},
   229  								{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   230  								{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
   231  							},
   232  						}),
   233  					},
   234  				},
   235  			},
   236  			nil,
   237  			nil,
   238  		},
   239  		{
   240  			"docker",
   241  			[]config.Publisher{
   242  				{
   243  					Name: "test",
   244  					IDs:  []string{"img", "mnf"},
   245  					Cmd:  MockCmd + " {{ .ArtifactName }}",
   246  					Env: []string{
   247  						MarshalMockEnv(&MockData{
   248  							AnyOf: []MockCall{
   249  								{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   250  								{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
   251  							},
   252  						}),
   253  					},
   254  				},
   255  			},
   256  			nil,
   257  			nil,
   258  		},
   259  		{
   260  			"extra files",
   261  			[]config.Publisher{
   262  				{
   263  					Name: "test",
   264  					Cmd:  MockCmd + " {{ .ArtifactName }}",
   265  					Env: []string{
   266  						MarshalMockEnv(&MockData{
   267  							AnyOf: []MockCall{
   268  								{ExpectedArgs: []string{"a.deb"}, ExitCode: 0, ExpectedEnv: osEnv()},
   269  								{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
   270  								{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   271  								{ExpectedArgs: []string{"a.txt"}, ExitCode: 0, ExpectedEnv: osEnv()},
   272  								{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   273  								{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
   274  							},
   275  						}),
   276  					},
   277  					ExtraFiles: []config.ExtraFile{
   278  						{Glob: filepath.Join("testdata", "*.txt")},
   279  					},
   280  				},
   281  			},
   282  			nil,
   283  			nil,
   284  		},
   285  		{
   286  			"extra files with rename",
   287  			[]config.Publisher{
   288  				{
   289  					Name: "test",
   290  					Cmd:  MockCmd + " {{ .ArtifactName }}",
   291  					Env: []string{
   292  						MarshalMockEnv(&MockData{
   293  							AnyOf: []MockCall{
   294  								{ExpectedArgs: []string{"a.deb"}, ExitCode: 0, ExpectedEnv: osEnv()},
   295  								{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
   296  								{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   297  								{ExpectedArgs: []string{"b.txt"}, ExitCode: 0, ExpectedEnv: osEnv()},
   298  								{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
   299  								{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
   300  							},
   301  						}),
   302  					},
   303  					ExtraFiles: []config.ExtraFile{
   304  						{
   305  							Glob:         filepath.Join("testdata", "*.txt"),
   306  							NameTemplate: "b.txt",
   307  						},
   308  					},
   309  				},
   310  			},
   311  			nil,
   312  			nil,
   313  		},
   314  		{
   315  			"try dir templating",
   316  			[]config.Publisher{
   317  				{
   318  					Name:      "test",
   319  					Signature: true,
   320  					IDs:       []string{"debpkg"},
   321  					Dir:       "{{ dir .ArtifactPath }}",
   322  					Cmd:       MockCmd + " {{ .ArtifactName }}",
   323  					Env: []string{
   324  						MarshalMockEnv(&MockData{
   325  							AnyOf: []MockCall{
   326  								{ExpectedArgs: []string{"a.deb"}, ExitCode: 0, ExpectedEnv: osEnv()},
   327  							},
   328  						}),
   329  					},
   330  				},
   331  			},
   332  			nil,
   333  			nil,
   334  		},
   335  		{
   336  			"check env templating",
   337  			[]config.Publisher{
   338  				{
   339  					Name: "test",
   340  					IDs:  []string{"debpkg"},
   341  					Cmd:  MockCmd,
   342  					Env: []string{
   343  						"PROJECT={{.ProjectName}}",
   344  						"ARTIFACT={{.ArtifactName}}",
   345  						"SECRET={{.Env.TEST_A_SECRET}}",
   346  						MarshalMockEnv(&MockData{
   347  							AnyOf: []MockCall{
   348  								{
   349  									ExpectedEnv: append(
   350  										[]string{"PROJECT=blah", "ARTIFACT=a.deb", "SECRET=x"},
   351  										osEnv()...,
   352  									),
   353  									ExitCode: 0,
   354  								},
   355  							},
   356  						}),
   357  					},
   358  				},
   359  			},
   360  			nil,
   361  			nil,
   362  		},
   363  		{
   364  			"override path",
   365  			[]config.Publisher{
   366  				{
   367  					Name: "test",
   368  					IDs:  []string{"debpkg"},
   369  					Cmd:  MockCmd,
   370  					Env: []string{
   371  						"PATH=/something-else",
   372  						MarshalMockEnv(&MockData{
   373  							AnyOf: []MockCall{
   374  								{
   375  									ExpectedEnv: append(
   376  										[]string{"PATH=/something-else"},
   377  										osEnv("PATH")...,
   378  									),
   379  									ExitCode: 0,
   380  								},
   381  							},
   382  						}),
   383  					},
   384  				},
   385  			},
   386  			nil,
   387  			nil,
   388  		},
   389  		{
   390  			"command error",
   391  			[]config.Publisher{
   392  				{
   393  					Disable: "true",
   394  				},
   395  				{
   396  					Name: "test",
   397  					IDs:  []string{"debpkg"},
   398  					Cmd:  MockCmd + " {{.ArtifactName}}",
   399  					Env: []string{
   400  						MarshalMockEnv(&MockData{
   401  							AnyOf: []MockCall{
   402  								{
   403  									ExpectedArgs: []string{"a.deb"},
   404  									ExpectedEnv:  osEnv(),
   405  									Stderr:       "test error",
   406  									ExitCode:     1,
   407  								},
   408  							},
   409  						}),
   410  					},
   411  				},
   412  			},
   413  			// stderr is sent to output via logger
   414  			fmt.Errorf(`publishing: %s failed: exit status 1: test error`, MockCmd),
   415  			nil,
   416  		},
   417  	}
   418  
   419  	for i, tc := range testCases {
   420  		t.Run(fmt.Sprintf("%d-%s", i, tc.name), func(t *testing.T) {
   421  			err := Execute(ctx, tc.publishers)
   422  			if tc.expectErr != nil {
   423  				require.Error(t, err)
   424  				require.True(t, strings.HasPrefix(err.Error(), tc.expectErr.Error()), err.Error())
   425  				return
   426  			}
   427  			if tc.expectErrAs != nil {
   428  				require.ErrorAs(t, err, tc.expectErrAs)
   429  				return
   430  			}
   431  			require.NoError(t, err)
   432  		})
   433  	}
   434  }