github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/checksums/checksums_test.go (about)

     1  package checksums
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"syscall"
     9  	"testing"
    10  
    11  	"github.com/goreleaser/goreleaser/internal/artifact"
    12  	"github.com/goreleaser/goreleaser/internal/testctx"
    13  	"github.com/goreleaser/goreleaser/internal/testlib"
    14  	"github.com/goreleaser/goreleaser/pkg/config"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestDescription(t *testing.T) {
    19  	require.NotEmpty(t, Pipe{}.String())
    20  }
    21  
    22  func TestPipe(t *testing.T) {
    23  	const binary = "binary"
    24  	const archive = binary + ".tar.gz"
    25  	const linuxPackage = binary + ".rpm"
    26  	const checksums = binary + "_bar_checksums.txt"
    27  	const sum = "61d034473102d7dac305902770471fd50f4c5b26f6831a56dd90b5184b3c30fc  "
    28  
    29  	tests := map[string]struct {
    30  		ids  []string
    31  		want string
    32  	}{
    33  		"default": {
    34  			want: strings.Join([]string{
    35  				sum + binary,
    36  				sum + linuxPackage,
    37  				sum + archive,
    38  			}, "\n") + "\n",
    39  		},
    40  		"select ids": {
    41  			ids: []string{
    42  				"id-1",
    43  				"id-2",
    44  			},
    45  			want: strings.Join([]string{
    46  				sum + binary,
    47  				sum + archive,
    48  			}, "\n") + "\n",
    49  		},
    50  	}
    51  	for name, tt := range tests {
    52  		t.Run(name, func(t *testing.T) {
    53  			folder := t.TempDir()
    54  			file := filepath.Join(folder, binary)
    55  			require.NoError(t, os.WriteFile(file, []byte("some string"), 0o644))
    56  			ctx := testctx.NewWithCfg(
    57  				config.Project{
    58  					Dist:        folder,
    59  					ProjectName: binary,
    60  					Checksum: config.Checksum{
    61  						NameTemplate: "{{ .ProjectName }}_{{ .Env.FOO }}_checksums.txt",
    62  						Algorithm:    "sha256",
    63  						IDs:          tt.ids,
    64  					},
    65  					Env: []string{"FOO=bar"},
    66  				},
    67  				testctx.WithCurrentTag("1.2.3"),
    68  			)
    69  			ctx.Artifacts.Add(&artifact.Artifact{
    70  				Name: binary,
    71  				Path: file,
    72  				Type: artifact.UploadableBinary,
    73  				Extra: map[string]interface{}{
    74  					artifact.ExtraID: "id-1",
    75  				},
    76  			})
    77  			ctx.Artifacts.Add(&artifact.Artifact{
    78  				Name: archive,
    79  				Path: file,
    80  				Type: artifact.UploadableArchive,
    81  				Extra: map[string]interface{}{
    82  					artifact.ExtraID: "id-2",
    83  				},
    84  			})
    85  			ctx.Artifacts.Add(&artifact.Artifact{
    86  				Name: linuxPackage,
    87  				Path: file,
    88  				Type: artifact.LinuxPackage,
    89  				Extra: map[string]interface{}{
    90  					artifact.ExtraID: "id-3",
    91  				},
    92  			})
    93  			require.NoError(t, Pipe{}.Run(ctx))
    94  			var artifacts []string
    95  			for _, a := range ctx.Artifacts.List() {
    96  				artifacts = append(artifacts, a.Name)
    97  				require.NoError(t, a.Refresh(), "refresh should not fail and yield same results as nothing changed")
    98  			}
    99  			require.Contains(t, artifacts, checksums, binary)
   100  			bts, err := os.ReadFile(filepath.Join(folder, checksums))
   101  			require.NoError(t, err)
   102  			require.Contains(t, tt.want, string(bts))
   103  		})
   104  	}
   105  }
   106  
   107  func TestPipeSplit(t *testing.T) {
   108  	const binary = "binary"
   109  	const archive = binary + ".tar.gz"
   110  	const linuxPackage = binary + ".rpm"
   111  	const sum = "61d034473102d7dac305902770471fd50f4c5b26f6831a56dd90b5184b3c30fc"
   112  
   113  	folder := t.TempDir()
   114  	file := filepath.Join(folder, binary)
   115  	require.NoError(t, os.WriteFile(file, []byte("some string"), 0o644))
   116  	ctx := testctx.NewWithCfg(
   117  		config.Project{
   118  			Dist:        folder,
   119  			ProjectName: "foo",
   120  			Checksum: config.Checksum{
   121  				Split: true,
   122  			},
   123  		},
   124  	)
   125  	ctx.Artifacts.Add(&artifact.Artifact{
   126  		Name: binary,
   127  		Path: file,
   128  		Type: artifact.UploadableBinary,
   129  		Extra: map[string]interface{}{
   130  			artifact.ExtraID: "id-1",
   131  		},
   132  	})
   133  	ctx.Artifacts.Add(&artifact.Artifact{
   134  		Name: archive,
   135  		Path: file,
   136  		Type: artifact.UploadableArchive,
   137  		Extra: map[string]interface{}{
   138  			artifact.ExtraID: "id-2",
   139  		},
   140  	})
   141  	ctx.Artifacts.Add(&artifact.Artifact{
   142  		Name: linuxPackage,
   143  		Path: file,
   144  		Type: artifact.LinuxPackage,
   145  		Extra: map[string]interface{}{
   146  			artifact.ExtraID: "id-3",
   147  		},
   148  	})
   149  	require.NoError(t, Pipe{}.Default(ctx))
   150  	require.NoError(t, Pipe{}.Run(ctx))
   151  
   152  	require.NoError(t, ctx.Artifacts.Visit(func(a *artifact.Artifact) error {
   153  		return a.Refresh()
   154  	}))
   155  
   156  	checks := ctx.Artifacts.Filter(artifact.ByType(artifact.Checksum)).List()
   157  	require.Len(t, checks, 3)
   158  
   159  	for _, check := range checks {
   160  		require.NotEmpty(t, check.Extra[artifact.ExtraChecksumOf])
   161  		bts, err := os.ReadFile(check.Path)
   162  		require.NoError(t, err)
   163  		require.Equal(t, sum, string(bts))
   164  	}
   165  }
   166  
   167  func TestRefreshModifying(t *testing.T) {
   168  	const binary = "binary"
   169  	folder := t.TempDir()
   170  	file := filepath.Join(folder, binary)
   171  	require.NoError(t, os.WriteFile(file, []byte("some string"), 0o644))
   172  	ctx := testctx.NewWithCfg(config.Project{
   173  		Dist:        folder,
   174  		ProjectName: binary,
   175  		Checksum: config.Checksum{
   176  			NameTemplate: "{{ .ProjectName }}_{{ .Env.FOO }}_checksums.txt",
   177  			Algorithm:    "sha256",
   178  		},
   179  		Env: []string{"FOO=bar"},
   180  	}, testctx.WithCurrentTag("1.2.3"))
   181  	ctx.Artifacts.Add(&artifact.Artifact{
   182  		Name: binary,
   183  		Path: file,
   184  		Type: artifact.UploadableBinary,
   185  	})
   186  	require.NoError(t, Pipe{}.Run(ctx))
   187  	checks := ctx.Artifacts.Filter(artifact.ByType(artifact.Checksum)).List()
   188  	require.Len(t, checks, 1)
   189  	previous, err := os.ReadFile(checks[0].Path)
   190  	require.NoError(t, err)
   191  	require.NoError(t, os.WriteFile(file, []byte("some other string"), 0o644))
   192  	require.NoError(t, checks[0].Refresh())
   193  	current, err := os.ReadFile(checks[0].Path)
   194  	require.NoError(t, err)
   195  	require.NotEqual(t, string(previous), string(current))
   196  }
   197  
   198  func TestRefreshModifyingSplit(t *testing.T) {
   199  	const binary = "binary"
   200  	folder := t.TempDir()
   201  	file := filepath.Join(folder, binary)
   202  	require.NoError(t, os.WriteFile(file, []byte("some string"), 0o644))
   203  	ctx := testctx.NewWithCfg(config.Project{
   204  		Dist:        folder,
   205  		ProjectName: binary,
   206  		Checksum: config.Checksum{
   207  			Split: true,
   208  		},
   209  		Env: []string{"FOO=bar"},
   210  	}, testctx.WithCurrentTag("1.2.3"))
   211  	ctx.Artifacts.Add(&artifact.Artifact{
   212  		Name: binary,
   213  		Path: file,
   214  		Type: artifact.UploadableBinary,
   215  	})
   216  	require.NoError(t, Pipe{}.Default(ctx))
   217  	require.NoError(t, Pipe{}.Run(ctx))
   218  	checks := ctx.Artifacts.Filter(artifact.ByType(artifact.Checksum)).List()
   219  	require.Len(t, checks, 1)
   220  	previous, err := os.ReadFile(checks[0].Path)
   221  	require.NoError(t, err)
   222  	require.NoError(t, os.WriteFile(file, []byte("some other string"), 0o644))
   223  	require.NoError(t, checks[0].Refresh())
   224  	current, err := os.ReadFile(checks[0].Path)
   225  	require.NoError(t, err)
   226  	require.NotEqual(t, string(previous), string(current))
   227  }
   228  
   229  func TestPipeFileNotExist(t *testing.T) {
   230  	folder := t.TempDir()
   231  	ctx := testctx.NewWithCfg(
   232  		config.Project{
   233  			Dist: folder,
   234  			Checksum: config.Checksum{
   235  				NameTemplate: "checksums.txt",
   236  			},
   237  		},
   238  		testctx.WithCurrentTag("1.2.3"),
   239  	)
   240  	ctx.Artifacts.Add(&artifact.Artifact{
   241  		Name: "nope",
   242  		Path: "/nope",
   243  		Type: artifact.UploadableBinary,
   244  	})
   245  	require.ErrorIs(t, Pipe{}.Run(ctx), os.ErrNotExist)
   246  }
   247  
   248  func TestPipeInvalidNameTemplate(t *testing.T) {
   249  	binFile, err := os.CreateTemp(t.TempDir(), "goreleasertest-bin")
   250  	require.NoError(t, err)
   251  	t.Cleanup(func() { require.NoError(t, binFile.Close()) })
   252  	_, err = binFile.WriteString("fake artifact")
   253  	require.NoError(t, err)
   254  
   255  	for _, template := range []string{
   256  		"{{ .Pro }_checksums.txt",
   257  		"{{.Env.NOPE}}",
   258  	} {
   259  		for _, split := range []bool{true, false} {
   260  			t.Run(fmt.Sprintf("split_%v_%s", split, template), func(t *testing.T) {
   261  				folder := t.TempDir()
   262  				ctx := testctx.NewWithCfg(
   263  					config.Project{
   264  						Dist:        folder,
   265  						ProjectName: "name",
   266  						Checksum: config.Checksum{
   267  							NameTemplate: template,
   268  							Algorithm:    "sha256",
   269  							Split:        split,
   270  						},
   271  					},
   272  					testctx.WithCurrentTag("1.2.3"),
   273  				)
   274  				ctx.Artifacts.Add(&artifact.Artifact{
   275  					Name: "whatever",
   276  					Type: artifact.UploadableBinary,
   277  					Path: binFile.Name(),
   278  				})
   279  				testlib.RequireTemplateError(t, Pipe{}.Run(ctx))
   280  			})
   281  		}
   282  	}
   283  }
   284  
   285  func TestPipeCouldNotOpenChecksumsTxt(t *testing.T) {
   286  	folder := t.TempDir()
   287  	binFile, err := os.CreateTemp(folder, "goreleasertest-bin")
   288  	require.NoError(t, err)
   289  	t.Cleanup(func() { require.NoError(t, binFile.Close()) })
   290  	_, err = binFile.WriteString("fake artifact")
   291  	require.NoError(t, err)
   292  
   293  	file := filepath.Join(folder, "checksums.txt")
   294  	require.NoError(t, os.WriteFile(file, []byte("some string"), 0o000))
   295  	ctx := testctx.NewWithCfg(
   296  		config.Project{
   297  			Dist: folder,
   298  			Checksum: config.Checksum{
   299  				NameTemplate: "checksums.txt",
   300  				Algorithm:    "sha256",
   301  			},
   302  		},
   303  		testctx.WithCurrentTag("1.2.3"),
   304  	)
   305  	ctx.Artifacts.Add(&artifact.Artifact{
   306  		Name: "whatever",
   307  		Type: artifact.UploadableBinary,
   308  		Path: binFile.Name(),
   309  	})
   310  	err = Pipe{}.Run(ctx)
   311  	require.Error(t, err)
   312  	require.ErrorIs(t, Pipe{}.Run(ctx), syscall.EACCES)
   313  }
   314  
   315  func TestPipeWhenNoArtifacts(t *testing.T) {
   316  	ctx := testctx.New()
   317  	require.NoError(t, Pipe{}.Run(ctx))
   318  	require.Empty(t, ctx.Artifacts.List())
   319  }
   320  
   321  func TestDefault(t *testing.T) {
   322  	ctx := testctx.NewWithCfg(config.Project{
   323  		Checksum: config.Checksum{},
   324  	})
   325  	require.NoError(t, Pipe{}.Default(ctx))
   326  	require.Equal(
   327  		t,
   328  		"{{ .ProjectName }}_{{ .Version }}_checksums.txt",
   329  		ctx.Config.Checksum.NameTemplate,
   330  	)
   331  	require.Equal(t, "sha256", ctx.Config.Checksum.Algorithm)
   332  }
   333  
   334  func TestDefaultSPlit(t *testing.T) {
   335  	ctx := testctx.NewWithCfg(config.Project{
   336  		Checksum: config.Checksum{
   337  			Split: true,
   338  		},
   339  	})
   340  	require.NoError(t, Pipe{}.Default(ctx))
   341  	require.Equal(
   342  		t,
   343  		"{{ .ArtifactName }}.{{ .Algorithm }}",
   344  		ctx.Config.Checksum.NameTemplate,
   345  	)
   346  	require.Equal(t, "sha256", ctx.Config.Checksum.Algorithm)
   347  }
   348  
   349  func TestDefaultSet(t *testing.T) {
   350  	ctx := testctx.NewWithCfg(config.Project{
   351  		Checksum: config.Checksum{
   352  			NameTemplate: "checksums.txt",
   353  		},
   354  	})
   355  	require.NoError(t, Pipe{}.Default(ctx))
   356  	require.Equal(t, "checksums.txt", ctx.Config.Checksum.NameTemplate)
   357  }
   358  
   359  func TestPipeChecksumsSortByFilename(t *testing.T) {
   360  	const binary = "binary"
   361  	const checksums = "checksums.txt"
   362  	const filePaths = "./testdata/order/*.txt"
   363  
   364  	folder := t.TempDir()
   365  	file := filepath.Join(folder, binary)
   366  	require.NoError(t, os.WriteFile(file, []byte("some string"), 0o644))
   367  
   368  	ctx := testctx.NewWithCfg(
   369  		config.Project{
   370  			Dist:        folder,
   371  			ProjectName: binary,
   372  			Checksum: config.Checksum{
   373  				Algorithm:    "sha256",
   374  				NameTemplate: "checksums.txt",
   375  				ExtraFiles: []config.ExtraFile{
   376  					{Glob: filePaths},
   377  				},
   378  			},
   379  		},
   380  	)
   381  
   382  	ctx.Artifacts.Add(&artifact.Artifact{
   383  		Name: binary,
   384  		Path: file,
   385  		Type: artifact.UploadableBinary,
   386  	})
   387  
   388  	require.NoError(t, Pipe{}.Run(ctx))
   389  
   390  	bts, err := os.ReadFile(filepath.Join(folder, checksums))
   391  	require.NoError(t, err)
   392  
   393  	lines := strings.Split(string(bts), "\n")
   394  
   395  	wantLinesOrder := []string{
   396  		"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb  a.txt",
   397  		"3b64db95cb55c763391c707108489ae18b4112d783300de38e033b4c98c3deaf  b.txt",
   398  		"61d034473102d7dac305902770471fd50f4c5b26f6831a56dd90b5184b3c30fc  binary",
   399  		"64daa44ad493ff28a96effab6e77f1732a3d97d83241581b37dbd70a7a4900fe  c.txt",
   400  		"5bf8aa57fc5a6bc547decf1cc6db63f10deb55a3c6c5df497d631fb3d95e1abf  d.txt",
   401  	}
   402  
   403  	for i, want := range wantLinesOrder {
   404  		require.Equal(t, want, lines[i])
   405  	}
   406  }
   407  
   408  func TestPipeCheckSumsWithExtraFiles(t *testing.T) {
   409  	const binary = "binary"
   410  	const checksums = "checksums.txt"
   411  	const extraFileFooRelPath = "./testdata/foo.txt"
   412  	const extraFileBarRelPath = "./testdata/**/bar.txt"
   413  	const extraFileFoo = "foo.txt"
   414  	const extraFileBar = "bar.txt"
   415  
   416  	tests := map[string]struct {
   417  		extraFiles []config.ExtraFile
   418  		ids        []string
   419  		want       []string
   420  	}{
   421  		"default": {
   422  			extraFiles: nil,
   423  			want: []string{
   424  				binary,
   425  			},
   426  		},
   427  		"one extra file": {
   428  			extraFiles: []config.ExtraFile{
   429  				{Glob: extraFileFooRelPath},
   430  			},
   431  			want: []string{
   432  				extraFileFoo,
   433  			},
   434  		},
   435  		"multiple extra files": {
   436  			extraFiles: []config.ExtraFile{
   437  				{Glob: extraFileFooRelPath},
   438  				{Glob: extraFileBarRelPath},
   439  			},
   440  			want: []string{
   441  				extraFileFoo,
   442  				extraFileBar,
   443  			},
   444  		},
   445  		"one extra file with no builds": {
   446  			extraFiles: []config.ExtraFile{
   447  				{Glob: extraFileFooRelPath},
   448  			},
   449  			ids: []string{"yada yada yada"},
   450  			want: []string{
   451  				extraFileFoo,
   452  			},
   453  		},
   454  	}
   455  
   456  	for name, tt := range tests {
   457  		t.Run(name, func(t *testing.T) {
   458  			folder := t.TempDir()
   459  			file := filepath.Join(folder, binary)
   460  			require.NoError(t, os.WriteFile(file, []byte("some string"), 0o644))
   461  			ctx := testctx.NewWithCfg(
   462  				config.Project{
   463  					Dist:        folder,
   464  					ProjectName: binary,
   465  					Checksum: config.Checksum{
   466  						Algorithm:    "sha256",
   467  						NameTemplate: "checksums.txt",
   468  						ExtraFiles:   tt.extraFiles,
   469  						IDs:          tt.ids,
   470  					},
   471  				},
   472  			)
   473  
   474  			ctx.Artifacts.Add(&artifact.Artifact{
   475  				Name: binary,
   476  				Path: file,
   477  				Type: artifact.UploadableBinary,
   478  				Extra: map[string]interface{}{
   479  					artifact.ExtraID: "id-1",
   480  				},
   481  			})
   482  
   483  			require.NoError(t, Pipe{}.Run(ctx))
   484  
   485  			bts, err := os.ReadFile(filepath.Join(folder, checksums))
   486  
   487  			require.NoError(t, err)
   488  			for _, want := range tt.want {
   489  				if tt.extraFiles == nil {
   490  					require.Contains(t, string(bts), "61d034473102d7dac305902770471fd50f4c5b26f6831a56dd90b5184b3c30fc  "+want)
   491  				} else {
   492  					require.Contains(t, string(bts), "3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  "+want)
   493  				}
   494  			}
   495  
   496  			_ = ctx.Artifacts.Visit(func(a *artifact.Artifact) error {
   497  				if a.Path != file {
   498  					return nil
   499  				}
   500  				if len(tt.ids) > 0 {
   501  					return nil
   502  				}
   503  				checkSum, err := artifact.Extra[string](*a, artifactChecksumExtra)
   504  				require.NoError(t, err)
   505  				require.NotEmptyf(t, checkSum, "failed: %v", a.Path)
   506  				return nil
   507  			})
   508  		})
   509  	}
   510  }
   511  
   512  func TestExtraFilesNoMatch(t *testing.T) {
   513  	dir := t.TempDir()
   514  	ctx := testctx.NewWithCfg(
   515  		config.Project{
   516  			Dist:        dir,
   517  			ProjectName: "fake",
   518  			Checksum: config.Checksum{
   519  				Algorithm:    "sha256",
   520  				NameTemplate: "checksums.txt",
   521  				ExtraFiles:   []config.ExtraFile{{Glob: "./nope/nope.txt"}},
   522  			},
   523  		},
   524  	)
   525  
   526  	ctx.Artifacts.Add(&artifact.Artifact{
   527  		Name: "fake",
   528  		Path: "fake-path",
   529  		Type: artifact.UploadableBinary,
   530  	})
   531  
   532  	require.NoError(t, Pipe{}.Default(ctx))
   533  	require.EqualError(t, Pipe{}.Run(ctx), `globbing failed for pattern ./nope/nope.txt: matching "./nope/nope.txt": file does not exist`)
   534  }
   535  
   536  func TestSkip(t *testing.T) {
   537  	t.Run("skip", func(t *testing.T) {
   538  		ctx := testctx.NewWithCfg(config.Project{
   539  			Checksum: config.Checksum{
   540  				Disable: true,
   541  			},
   542  		})
   543  		require.True(t, Pipe{}.Skip(ctx))
   544  	})
   545  
   546  	t.Run("dont skip", func(t *testing.T) {
   547  		require.False(t, Pipe{}.Skip(testctx.New()))
   548  	})
   549  }
   550  
   551  // TODO: add tests for LinuxPackage and UploadableSourceArchive