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