github.com/goreleaser/nfpm/v2@v2.44.0/acceptance_test.go (about)

     1  //go:build acceptance
     2  
     3  package nfpm_test
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/goreleaser/nfpm/v2"
    14  	_ "github.com/goreleaser/nfpm/v2/apk"
    15  	_ "github.com/goreleaser/nfpm/v2/arch"
    16  	_ "github.com/goreleaser/nfpm/v2/deb"
    17  	_ "github.com/goreleaser/nfpm/v2/ipk"
    18  	_ "github.com/goreleaser/nfpm/v2/rpm"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  // nolint: gochecknoglobals
    23  var formatArchs = map[string][]string{
    24  	"apk":       {"amd64", "arm64", "386", "ppc64le", "armv6", "armv7", "s390x"},
    25  	"deb":       {"amd64", "arm64", "ppc64le", "armv7", "s390x"},
    26  	"ipk":       {"x86_64", "aarch64_generic"},
    27  	"rpm":       {"amd64", "arm64", "ppc64le"},
    28  	"archlinux": {"amd64"},
    29  }
    30  
    31  func TestCore(t *testing.T) {
    32  	t.Parallel()
    33  	testNames := []string{
    34  		"min",
    35  		"simple",
    36  		"no-glob",
    37  		"complex",
    38  		"env-var-version",
    39  		"overrides",
    40  		"meta",
    41  		"withchangelog",
    42  		"symlink",
    43  		"signed",
    44  	}
    45  	for _, name := range testNames {
    46  		for format, architecture := range formatArchs {
    47  			for _, arch := range architecture {
    48  				func(t *testing.T, testName, testFormat, testArch string) {
    49  					t.Run(fmt.Sprintf("%s/%s/%s", testFormat, testArch, testName), func(t *testing.T) {
    50  						t.Parallel()
    51  						if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
    52  							t.Skip("ppc64le arch not supported in pipeline")
    53  						}
    54  						accept(t, acceptParms{
    55  							Name:   fmt.Sprintf("%s_%s", testName, testArch),
    56  							Conf:   fmt.Sprintf("core.%s.yaml", testName),
    57  							Format: testFormat,
    58  							Docker: dockerParams{
    59  								File:   fmt.Sprintf("%s.dockerfile", testFormat),
    60  								Target: testName,
    61  								Arch:   testArch,
    62  							},
    63  						})
    64  					})
    65  				}(t, name, format, arch)
    66  			}
    67  		}
    68  	}
    69  }
    70  
    71  func TestUpgrade(t *testing.T) {
    72  	t.Parallel()
    73  	testNames := []string{
    74  		"upgrade",
    75  	}
    76  	for _, name := range testNames {
    77  		for format, architecture := range formatArchs {
    78  			for _, arch := range architecture {
    79  				func(t *testing.T, testName, testFormat, testArch string) {
    80  					t.Run(fmt.Sprintf("%s/%s/%s", testFormat, testArch, testName), func(t *testing.T) {
    81  						t.Parallel()
    82  						if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
    83  							t.Skip("ppc64le arch not supported in pipeline")
    84  						}
    85  
    86  						arch := strings.ReplaceAll(testArch, "armv", "arm/")
    87  						oldpkg := fmt.Sprintf("tmp/%s_%s.v1.%s", testName, testArch, testFormat)
    88  						target := fmt.Sprintf("./testdata/acceptance/%s", oldpkg)
    89  						require.NoError(t, os.MkdirAll("./testdata/acceptance/tmp", 0o700))
    90  
    91  						config, err := nfpm.ParseFileWithEnvMapping(fmt.Sprintf("./testdata/acceptance/%s.v1.yaml", testName),
    92  							func(s string) string {
    93  								switch s {
    94  								case "BUILD_ARCH":
    95  									return strings.ReplaceAll(arch, "/", "")
    96  								case "SEMVER":
    97  									return "v1.0.0-0.1.b1+git.abcdefgh"
    98  								default:
    99  									return os.Getenv(s)
   100  								}
   101  							},
   102  						)
   103  						require.NoError(t, err)
   104  
   105  						info, err := config.Get(testFormat)
   106  						require.NoError(t, err)
   107  						require.NoError(t, nfpm.Validate(info))
   108  
   109  						pkg, err := nfpm.Get(testFormat)
   110  						require.NoError(t, err)
   111  
   112  						f, err := os.Create(target)
   113  						require.NoError(t, err)
   114  						t.Cleanup(func() { require.NoError(t, f.Close()) })
   115  						info.Target = target
   116  						require.NoError(t, pkg.Package(nfpm.WithDefaults(info), f))
   117  
   118  						accept(t, acceptParms{
   119  							Name:   fmt.Sprintf("%s_%s.v2", testName, testArch),
   120  							Conf:   fmt.Sprintf("%s.v2.yaml", testName),
   121  							Format: testFormat,
   122  							Docker: dockerParams{
   123  								File:      fmt.Sprintf("%s.dockerfile", testFormat),
   124  								Target:    testName,
   125  								Arch:      testArch,
   126  								BuildArgs: []string{fmt.Sprintf("oldpackage=%s", oldpkg)},
   127  							},
   128  						})
   129  					})
   130  				}(t, name, format, arch)
   131  			}
   132  		}
   133  	}
   134  }
   135  
   136  func TestRPMCompression(t *testing.T) {
   137  	t.Parallel()
   138  	format := "rpm"
   139  	compressFormats := []string{"gzip", "xz", "lzma", "zstd"}
   140  	for _, arch := range formatArchs[format] {
   141  		for _, compFormat := range compressFormats {
   142  			func(t *testing.T, testCompFormat, testArch string) {
   143  				t.Run(fmt.Sprintf("%s/%s/%s", format, testArch, testCompFormat), func(t *testing.T) {
   144  					t.Parallel()
   145  					if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
   146  						t.Skip("ppc64le arch not supported in pipeline")
   147  					}
   148  					accept(t, acceptParms{
   149  						Name:   fmt.Sprintf("%s_compression_%s", testCompFormat, testArch),
   150  						Conf:   fmt.Sprintf("rpm.%s.compression.yaml", testCompFormat),
   151  						Format: format,
   152  						Docker: dockerParams{
   153  							File:      fmt.Sprintf("%s.dockerfile", format),
   154  							Target:    "compression",
   155  							Arch:      testArch,
   156  							BuildArgs: []string{fmt.Sprintf("compression=%s", testCompFormat)},
   157  						},
   158  					})
   159  				})
   160  			}(t, compFormat, arch)
   161  		}
   162  	}
   163  }
   164  
   165  func TestDebCompression(t *testing.T) {
   166  	t.Parallel()
   167  	format := "deb"
   168  	compressFormats := []string{"gzip", "xz", "zstd", "none"}
   169  	for _, arch := range formatArchs[format] {
   170  		for _, compFormat := range compressFormats {
   171  			func(t *testing.T, testCompFormat, testArch string) {
   172  				t.Run(fmt.Sprintf("%s/%s/%s", format, testArch, testCompFormat), func(t *testing.T) {
   173  					t.Parallel()
   174  					if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
   175  						t.Skip("ppc64le arch not supported in pipeline")
   176  					}
   177  
   178  					accept(t, acceptParms{
   179  						Name:   fmt.Sprintf("%s_compression_%s", testCompFormat, testArch),
   180  						Conf:   fmt.Sprintf("deb.%s.compression.yaml", testCompFormat),
   181  						Format: format,
   182  						Docker: dockerParams{
   183  							File:   fmt.Sprintf("%s.dockerfile", format),
   184  							Target: "compression",
   185  							Arch:   testArch,
   186  						},
   187  					})
   188  				})
   189  			}(t, compFormat, arch)
   190  		}
   191  	}
   192  }
   193  
   194  func TestRPMSpecific(t *testing.T) {
   195  	t.Parallel()
   196  	format := "rpm"
   197  	testNames := []string{
   198  		"release",
   199  		"directories",
   200  		"verify",
   201  	}
   202  	for _, name := range testNames {
   203  		for _, arch := range formatArchs[format] {
   204  			func(t *testing.T, testName, testArch string) {
   205  				t.Run(fmt.Sprintf("%s/%s/%s", format, testArch, testName), func(t *testing.T) {
   206  					t.Parallel()
   207  					if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
   208  						t.Skip("ppc64le arch not supported in pipeline")
   209  					}
   210  					accept(t, acceptParms{
   211  						Name:   fmt.Sprintf("%s_%s", testName, testArch),
   212  						Conf:   fmt.Sprintf("%s.%s.yaml", format, testName),
   213  						Format: format,
   214  						Docker: dockerParams{
   215  							File:   fmt.Sprintf("%s.dockerfile", format),
   216  							Target: testName,
   217  							Arch:   testArch,
   218  						},
   219  					})
   220  				})
   221  			}(t, name, arch)
   222  		}
   223  	}
   224  }
   225  
   226  func TestDebSpecific(t *testing.T) {
   227  	t.Parallel()
   228  	format := "deb"
   229  	testNames := []string{
   230  		"rules",
   231  		"triggers",
   232  		"breaks",
   233  		"predepends",
   234  	}
   235  	for _, name := range testNames {
   236  		for _, arch := range formatArchs[format] {
   237  			func(t *testing.T, testName, testArch string) {
   238  				t.Run(fmt.Sprintf("%s/%s/%s", format, testArch, testName), func(t *testing.T) {
   239  					t.Parallel()
   240  					if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
   241  						t.Skip("ppc64le arch not supported in pipeline")
   242  					}
   243  					accept(t, acceptParms{
   244  						Name:   fmt.Sprintf("%s_%s", testName, testArch),
   245  						Conf:   fmt.Sprintf("%s.%s.yaml", format, testName),
   246  						Format: format,
   247  						Docker: dockerParams{
   248  							File:   fmt.Sprintf("%s.dockerfile", format),
   249  							Target: testName,
   250  							Arch:   testArch,
   251  						},
   252  					})
   253  				})
   254  			}(t, name, arch)
   255  		}
   256  	}
   257  }
   258  
   259  func TestIPKSpecific(t *testing.T) {
   260  	t.Parallel()
   261  	format := "ipk"
   262  	testNames := []string{
   263  		"alternatives",
   264  		"conflicts",
   265  		"predepends",
   266  	}
   267  	for _, name := range testNames {
   268  		for _, arch := range formatArchs[format] {
   269  			func(t *testing.T, testName, testArch string) {
   270  				t.Run(fmt.Sprintf("%s/%s/%s", format, testArch, testName), func(t *testing.T) {
   271  					t.Parallel()
   272  					if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
   273  						t.Skip("ppc64le arch not supported in pipeline")
   274  					}
   275  					accept(t, acceptParms{
   276  						Name:   fmt.Sprintf("%s_%s", testName, testArch),
   277  						Conf:   fmt.Sprintf("%s.%s.yaml", format, testName),
   278  						Format: format,
   279  						Docker: dockerParams{
   280  							File:   fmt.Sprintf("%s.dockerfile", format),
   281  							Target: testName,
   282  							Arch:   testArch,
   283  						},
   284  					})
   285  				})
   286  			}(t, name, arch)
   287  		}
   288  	}
   289  }
   290  
   291  func TestRPMSign(t *testing.T) {
   292  	for _, os := range []string{
   293  		"centos9",
   294  		"centos10",
   295  		"fedora40",
   296  		"fedora41",
   297  	} {
   298  		os := os
   299  		t.Run(fmt.Sprintf("rpm/amd64/sign/%s", os), func(t *testing.T) {
   300  			accept(t, acceptParms{
   301  				Name:   fmt.Sprintf("sign_%s_amd64", os),
   302  				Conf:   "core.signed.yaml",
   303  				Format: "rpm",
   304  				Docker: dockerParams{
   305  					File:   fmt.Sprintf("rpm_%s.dockerfile", os),
   306  					Target: "signed",
   307  					Arch:   "amd64",
   308  				},
   309  			})
   310  		})
   311  	}
   312  }
   313  
   314  func TestDebSign(t *testing.T) {
   315  	t.Parallel()
   316  	for _, arch := range formatArchs["deb"] {
   317  		for _, sigtype := range []string{"dpkg-sig", "debsign"} {
   318  			func(t *testing.T, testSigtype, testArch string) {
   319  				t.Run(fmt.Sprintf("deb/%s/%s", testArch, testSigtype), func(t *testing.T) {
   320  					t.Parallel()
   321  					target := "signed"
   322  					if testSigtype == "dpkg-sig" {
   323  						target = "dpkg-signed"
   324  					}
   325  					if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
   326  						t.Skip("ppc64le arch not supported in pipeline")
   327  					}
   328  					accept(t, acceptParms{
   329  						Name:   fmt.Sprintf("%s_sign_%s", testSigtype, testArch),
   330  						Conf:   fmt.Sprintf("deb.%s.sign.yaml", testSigtype),
   331  						Format: "deb",
   332  						Docker: dockerParams{
   333  							File:   "deb.dockerfile",
   334  							Target: target,
   335  							Arch:   testArch,
   336  						},
   337  					})
   338  				})
   339  			}(t, sigtype, arch)
   340  		}
   341  	}
   342  }
   343  
   344  type acceptParms struct {
   345  	Name   string
   346  	Conf   string
   347  	Format string
   348  	Docker dockerParams
   349  }
   350  
   351  type dockerParams struct {
   352  	File      string
   353  	Target    string
   354  	Arch      string
   355  	BuildArgs []string
   356  }
   357  
   358  func accept(t *testing.T, params acceptParms) {
   359  	t.Helper()
   360  
   361  	arch := strings.ReplaceAll(params.Docker.Arch, "armv", "arm/")
   362  	configFile := filepath.Join("./testdata/acceptance/", params.Conf)
   363  	tmp, err := filepath.Abs("./testdata/acceptance/tmp")
   364  	require.NoError(t, err)
   365  	packageName := params.Name + "." + params.Format
   366  	target := filepath.Join(tmp, packageName)
   367  	require.NoError(t, os.MkdirAll(tmp, 0o700))
   368  
   369  	envFunc := func(s string) string {
   370  		switch s {
   371  		case "BUILD_ARCH":
   372  			return strings.ReplaceAll(arch, "/", "")
   373  		case "SEMVER":
   374  			return "v1.0.0-0.1.b1+git.abcdefgh"
   375  		default:
   376  			return os.Getenv(s)
   377  		}
   378  	}
   379  	config, err := nfpm.ParseFileWithEnvMapping(configFile, envFunc)
   380  	require.NoError(t, err)
   381  
   382  	info, err := config.Get(params.Format)
   383  	require.NoError(t, err)
   384  	require.NoError(t, nfpm.Validate(info))
   385  
   386  	pkg, err := nfpm.Get(params.Format)
   387  	require.NoError(t, err)
   388  
   389  	cmdArgs := []string{
   390  		"build", "--rm", "--force-rm",
   391  		"--platform", fmt.Sprintf("linux/%s", arch),
   392  		"-f", params.Docker.File,
   393  		"--target", params.Docker.Target,
   394  		"--build-arg", "package=" + filepath.Join("tmp", packageName),
   395  	}
   396  	for _, arg := range params.Docker.BuildArgs {
   397  		cmdArgs = append(cmdArgs, "--build-arg", arg)
   398  	}
   399  	cmdArgs = append(cmdArgs, ".")
   400  
   401  	f, err := os.OpenFile(target, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o764)
   402  	require.NoError(t, err)
   403  	info.Target = target
   404  	require.NoError(t, pkg.Package(nfpm.WithDefaults(info), f))
   405  	//nolint:gosec
   406  	cmd := exec.Command("docker", cmdArgs...)
   407  	cmd.Dir = "./testdata/acceptance"
   408  	bts, err := cmd.CombinedOutput()
   409  	require.NoError(
   410  		t,
   411  		err,
   412  		"failed: %v; env BUILD_ARCH: %s; package: %s; output: %s",
   413  		cmd.Args,
   414  		envFunc("BUILD_ARCH"),
   415  		target,
   416  		string(bts),
   417  	)
   418  }