github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/gomod/gomod_proxy_test.go (about)

     1  package gomod
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"runtime"
     9  	"syscall"
    10  	"testing"
    11  
    12  	"github.com/goreleaser/goreleaser/internal/testctx"
    13  	"github.com/goreleaser/goreleaser/internal/testlib"
    14  	"github.com/goreleaser/goreleaser/pkg/config"
    15  	"github.com/goreleaser/goreleaser/pkg/context"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestString(t *testing.T) {
    20  	require.NotEmpty(t, CheckGoModPipe{}.String())
    21  	require.NotEmpty(t, ProxyPipe{}.String())
    22  }
    23  
    24  func TestCheckGoMod(t *testing.T) {
    25  	t.Run("replace on snapshot", func(t *testing.T) {
    26  		dir := testlib.Mktmp(t)
    27  		dist := filepath.Join(dir, "dist")
    28  		ctx := testctx.NewWithCfg(config.Project{
    29  			Dist: dist,
    30  			GoMod: config.GoMod{
    31  				Proxy:    true,
    32  				GoBinary: "go",
    33  			},
    34  			Builds: []config.Build{
    35  				{
    36  					ID:     "foo",
    37  					Goos:   []string{runtime.GOOS},
    38  					Goarch: []string{runtime.GOARCH},
    39  					Main:   ".",
    40  					Dir:    ".",
    41  				},
    42  			},
    43  		}, testctx.Snapshot, withGoReleaserModulePath)
    44  
    45  		fakeGoModAndSum(t, ctx.ModulePath)
    46  		require.NoError(t, exec.Command("go", "mod", "edit", "-replace", "foo=../bar").Run())
    47  		require.NoError(t, CheckGoModPipe{}.Run(ctx))
    48  	})
    49  	t.Run("no go mod", func(t *testing.T) {
    50  		dir := testlib.Mktmp(t)
    51  		dist := filepath.Join(dir, "dist")
    52  		ctx := testctx.NewWithCfg(config.Project{
    53  			Dist: dist,
    54  			GoMod: config.GoMod{
    55  				Proxy:    true,
    56  				GoBinary: "go",
    57  			},
    58  			Builds: []config.Build{
    59  				{
    60  					ID:     "foo",
    61  					Goos:   []string{runtime.GOOS},
    62  					Goarch: []string{runtime.GOARCH},
    63  					Main:   ".",
    64  					Dir:    ".",
    65  				},
    66  			},
    67  		}, withGoReleaserModulePath)
    68  
    69  		require.NoError(t, CheckGoModPipe{}.Run(ctx))
    70  	})
    71  	t.Run("replace", func(t *testing.T) {
    72  		dir := testlib.Mktmp(t)
    73  		dist := filepath.Join(dir, "dist")
    74  		ctx := testctx.NewWithCfg(config.Project{
    75  			Dist: dist,
    76  			GoMod: config.GoMod{
    77  				Proxy:    true,
    78  				GoBinary: "go",
    79  			},
    80  			Builds: []config.Build{
    81  				{
    82  					ID:     "foo",
    83  					Goos:   []string{runtime.GOOS},
    84  					Goarch: []string{runtime.GOARCH},
    85  					Main:   ".",
    86  					Dir:    ".",
    87  				},
    88  			},
    89  		}, withGoReleaserModulePath)
    90  
    91  		fakeGoModAndSum(t, ctx.ModulePath)
    92  		require.NoError(t, exec.Command("go", "mod", "edit", "-replace", "foo=../bar").Run())
    93  		require.ErrorIs(t, CheckGoModPipe{}.Run(ctx), ErrReplaceWithProxy)
    94  	})
    95  }
    96  
    97  func TestGoModProxy(t *testing.T) {
    98  	t.Run("goreleaser", func(t *testing.T) {
    99  		dir := testlib.Mktmp(t)
   100  		dist := filepath.Join(dir, "dist")
   101  		ctx := testctx.NewWithCfg(config.Project{
   102  			Dist: dist,
   103  			GoMod: config.GoMod{
   104  				Proxy:    true,
   105  				GoBinary: "go",
   106  			},
   107  			Builds: []config.Build{
   108  				{
   109  					ID:     "foo",
   110  					Goos:   []string{runtime.GOOS},
   111  					Goarch: []string{runtime.GOARCH},
   112  					Main:   ".",
   113  					Dir:    ".",
   114  				},
   115  			},
   116  		}, testctx.WithCurrentTag("v0.161.1"), withGoReleaserModulePath)
   117  
   118  		fakeGoModAndSum(t, ctx.ModulePath)
   119  		require.NoError(t, ProxyPipe{}.Run(ctx))
   120  		requireGoMod(t)
   121  		require.Equal(t, ctx.ModulePath, ctx.Config.Builds[0].Main)
   122  		require.Equal(t, ".", ctx.Config.Builds[0].UnproxiedMain)
   123  		require.Equal(t, filepath.Join(dist, "proxy", "foo"), ctx.Config.Builds[0].Dir)
   124  		require.Equal(t, ".", ctx.Config.Builds[0].UnproxiedDir)
   125  	})
   126  
   127  	t.Run("nfpm", func(t *testing.T) {
   128  		dir := testlib.Mktmp(t)
   129  		dist := filepath.Join(dir, "dist")
   130  		ctx := testctx.NewWithCfg(config.Project{
   131  			Dist: dist,
   132  			GoMod: config.GoMod{
   133  				Proxy:    true,
   134  				GoBinary: "go",
   135  			},
   136  			Builds: []config.Build{
   137  				{
   138  					ID:     "foo",
   139  					Goos:   []string{runtime.GOOS},
   140  					Goarch: []string{runtime.GOARCH},
   141  					Main:   "./cmd/nfpm",
   142  				},
   143  			},
   144  		}, testctx.WithCurrentTag("v2.3.1"), withNfpmModulePath)
   145  		fakeGoModAndSum(t, ctx.ModulePath)
   146  		require.NoError(t, ProxyPipe{}.Run(ctx))
   147  		requireGoMod(t)
   148  		require.Equal(t, ctx.ModulePath+"/cmd/nfpm", ctx.Config.Builds[0].Main)
   149  		require.Equal(t, filepath.Join(dist, "proxy", "foo"), ctx.Config.Builds[0].Dir)
   150  	})
   151  
   152  	// this repo does not have a go.sum file, which is ok, a project might not have any dependencies
   153  	t.Run("no go.sum", func(t *testing.T) {
   154  		dir := testlib.Mktmp(t)
   155  		dist := filepath.Join(dir, "dist")
   156  		ctx := testctx.NewWithCfg(config.Project{
   157  			Dist: dist,
   158  			GoMod: config.GoMod{
   159  				Proxy:    true,
   160  				GoBinary: "go",
   161  			},
   162  			Builds: []config.Build{
   163  				{
   164  					ID:     "foo",
   165  					Goos:   []string{runtime.GOOS},
   166  					Goarch: []string{runtime.GOARCH},
   167  				},
   168  			},
   169  		}, testctx.WithCurrentTag("v0.0.1"), withExampleModulePath)
   170  		fakeGoMod(t, ctx.ModulePath)
   171  		require.NoError(t, ProxyPipe{}.Run(ctx))
   172  		requireGoMod(t)
   173  		require.Equal(t, ctx.ModulePath, ctx.Config.Builds[0].Main)
   174  		require.Equal(t, filepath.Join(dist, "proxy", "foo"), ctx.Config.Builds[0].Dir)
   175  	})
   176  
   177  	t.Run("no perms", func(t *testing.T) {
   178  		for file, mode := range map[string]os.FileMode{
   179  			"go.mod":          0o500,
   180  			"go.sum":          0o500,
   181  			"../../../go.sum": 0o300,
   182  		} {
   183  			t.Run(file, func(t *testing.T) {
   184  				dir := testlib.Mktmp(t)
   185  				dist := filepath.Join(dir, "dist")
   186  				ctx := testctx.NewWithCfg(config.Project{
   187  					Dist: dist,
   188  					GoMod: config.GoMod{
   189  						Proxy:    true,
   190  						GoBinary: "go",
   191  					},
   192  					Builds: []config.Build{
   193  						{
   194  							ID:     "foo",
   195  							Goos:   []string{runtime.GOOS},
   196  							Goarch: []string{runtime.GOARCH},
   197  						},
   198  					},
   199  				}, withGoReleaserModulePath, testctx.WithCurrentTag("v0.161.1"))
   200  
   201  				fakeGoModAndSum(t, ctx.ModulePath)
   202  				require.NoError(t, ProxyPipe{}.Run(ctx)) // should succeed at first
   203  
   204  				// change perms of a file and run again, which should now fail on that file.
   205  				require.NoError(t, os.Chmod(filepath.Join(dist, "proxy", "foo", file), mode))
   206  				require.ErrorIs(t, ProxyPipe{}.Run(ctx), syscall.EACCES)
   207  			})
   208  		}
   209  	})
   210  
   211  	t.Run("goreleaser with main.go", func(t *testing.T) {
   212  		dir := testlib.Mktmp(t)
   213  		dist := filepath.Join(dir, "dist")
   214  		ctx := testctx.NewWithCfg(config.Project{
   215  			Dist: dist,
   216  			GoMod: config.GoMod{
   217  				Proxy:    true,
   218  				GoBinary: "go",
   219  			},
   220  			Builds: []config.Build{
   221  				{
   222  					ID:     "foo",
   223  					Goos:   []string{runtime.GOOS},
   224  					Goarch: []string{runtime.GOARCH},
   225  					Main:   "main.go",
   226  				},
   227  			},
   228  		}, withGoReleaserModulePath, testctx.WithCurrentTag("v0.161.1"))
   229  
   230  		fakeGoModAndSum(t, ctx.ModulePath)
   231  		require.NoError(t, ProxyPipe{}.Run(ctx))
   232  		requireGoMod(t)
   233  		require.Equal(t, ctx.ModulePath, ctx.Config.Builds[0].Main)
   234  		require.Equal(t, filepath.Join(dist, "proxy", "foo"), ctx.Config.Builds[0].Dir)
   235  	})
   236  }
   237  
   238  func TestProxyDescription(t *testing.T) {
   239  	require.NotEmpty(t, ProxyPipe{}.String())
   240  }
   241  
   242  func TestSkip(t *testing.T) {
   243  	t.Run("skip false gomod.proxy", func(t *testing.T) {
   244  		ctx := testctx.New()
   245  		require.True(t, ProxyPipe{}.Skip(ctx))
   246  		require.True(t, CheckGoModPipe{}.Skip(ctx))
   247  	})
   248  
   249  	t.Run("skip snapshot", func(t *testing.T) {
   250  		ctx := testctx.NewWithCfg(config.Project{
   251  			GoMod: config.GoMod{
   252  				Proxy: true,
   253  			},
   254  		}, withGoReleaserModulePath, testctx.Snapshot)
   255  		require.True(t, ProxyPipe{}.Skip(ctx))
   256  		require.False(t, CheckGoModPipe{}.Skip(ctx))
   257  	})
   258  
   259  	t.Run("skip not a go module", func(t *testing.T) {
   260  		ctx := testctx.NewWithCfg(config.Project{
   261  			GoMod: config.GoMod{
   262  				Proxy: true,
   263  			},
   264  		}, func(ctx *context.Context) { ctx.ModulePath = "" })
   265  		require.True(t, ProxyPipe{}.Skip(ctx))
   266  		require.True(t, CheckGoModPipe{}.Skip(ctx))
   267  	})
   268  
   269  	t.Run("dont skip", func(t *testing.T) {
   270  		ctx := testctx.NewWithCfg(config.Project{
   271  			GoMod: config.GoMod{
   272  				Proxy: true,
   273  			},
   274  		}, withGoReleaserModulePath)
   275  		require.False(t, ProxyPipe{}.Skip(ctx))
   276  		require.False(t, CheckGoModPipe{}.Skip(ctx))
   277  	})
   278  }
   279  
   280  func requireGoMod(tb testing.TB) {
   281  	tb.Helper()
   282  
   283  	mod, err := os.ReadFile("dist/proxy/foo/go.mod")
   284  	require.NoError(tb, err)
   285  	require.Contains(tb, string(mod), `module foo
   286  
   287  go 1.22`)
   288  }
   289  
   290  func fakeGoModAndSum(tb testing.TB, module string) {
   291  	tb.Helper()
   292  
   293  	fakeGoMod(tb, module)
   294  	require.NoError(tb, os.WriteFile("go.sum", []byte("\n"), 0o666))
   295  }
   296  
   297  func fakeGoMod(tb testing.TB, module string) {
   298  	tb.Helper()
   299  	require.NoError(tb, os.WriteFile("go.mod", []byte(fmt.Sprintf("module %s\n", module)), 0o666))
   300  }
   301  
   302  func withGoReleaserModulePath(ctx *context.Context) {
   303  	ctx.ModulePath = "github.com/goreleaser/goreleaser"
   304  }
   305  
   306  func withNfpmModulePath(ctx *context.Context) {
   307  	ctx.ModulePath = "github.com/goreleaser/nfpm/v2"
   308  }
   309  
   310  func withExampleModulePath(ctx *context.Context) {
   311  	ctx.ModulePath = "github.com/goreleaser/example-mod-proxy"
   312  }