Repository: goreleaser/nfpm
Pull request #611 (2023-01-29 15:13:50)

feat: add zstd compression support for deb and rpm
This PR adds `zstd` compression support for `deb` and `rpm`. For `deb`, an exception for the acceptance tests was needed as `zstd` is not yet supported in the debian base image. Due to `rpmpack`, `zstd` was already supported for `rpms` and we already tested it in our `rpm` tests but it was not documented, yet.

codecov[bot]: # [Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/611?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) Report
> Merging [#611](https://codecov.io/gh/goreleaser/nfpm/pull/611?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (e1d2379) into [main](https://codecov.io/gh/goreleaser/nfpm/commit/fe31c58444c71448f28efaf4f03a2a93e332ef44?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (fe31c58) will **decrease** coverage by `0.04%`.
> The diff coverage is `50.00%`.

```diff
@@            Coverage Diff             @@
##             main     #611      +/-   ##
==========================================
- Coverage   70.52%   70.48%   -0.04%     
==========================================
  Files          21       21              
  Lines        3162     3168       +6     
==========================================
+ Hits         2230     2233       +3     
- Misses        715      717       +2     
- Partials      217      218       +1     
```


| [Impacted Files](https://codecov.io/gh/goreleaser/nfpm/pull/611?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) | Coverage Δ | |
|---|---|---|
| [deb/deb.go](https://codecov.io/gh/goreleaser/nfpm/pull/611?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-ZGViL2RlYi5nbw==) | `71.50% <50.00%> (-0.24%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser)


Patch:
diff --git a/deb/deb.go b/deb/deb.go
index 4062c2e..cf7526b 100644
--- a/deb/deb.go
+++ b/deb/deb.go
@@ -21,6 +21,7 @@ import (
 	"github.com/goreleaser/nfpm/v2/deprecation"
 	"github.com/goreleaser/nfpm/v2/files"
 	"github.com/goreleaser/nfpm/v2/internal/sign"
+	"github.com/klauspost/compress/zstd"
 	gzip "github.com/klauspost/pgzip"
 	"github.com/ulikunitz/xz"
 )
@@ -312,6 +313,12 @@ func createDataTarball(info *nfpm.Info) (dataTarBall, md5sums []byte,
 			return nil, nil, 0, "", err
 		}
 		name = "data.tar.xz"
+	case "zstd":
+		dataTarballWriteCloser, err = zstd.NewWriter(&dataTarball)
+		if err != nil {
+			return nil, nil, 0, "", err
+		}
+		name = "data.tar.zst"
 	case "none":
 		dataTarballWriteCloser = nopCloser{Writer: &dataTarball}
 		name = "data.tar"
diff --git a/www/docs/configuration.md b/www/docs/configuration.md
index c521c65..448c024 100644
--- a/www/docs/configuration.md
+++ b/www/docs/configuration.md
@@ -298,8 +298,8 @@ rpm:
   # This will expand any env var you set in the field, e.g. packager: ${PACKAGER}
   packager: GoReleaser <staff@goreleaser.com>
 
-  # Compression algorithm (gzip (default), lzma or xz).
-  compression: lzma
+  # Compression algorithm (gzip (default), zstd, lzma or xz).
+  compression: zstd
 
   # The package is signed if a key_file is set
   signature:
@@ -349,8 +349,8 @@ deb:
   breaks:
     - some-package
 
-  # Compression algorithm (gzip (default), xz or none).
-  compression: xz
+  # Compression algorithm (gzip (default), zstd, xz or none).
+  compression: zstd
 
   # The package is signed if a key_file is set
   signature:


Test patch:
diff --git a/acceptance_test.go b/acceptance_test.go
index 8e951b6..320e667 100644
--- a/acceptance_test.go
+++ b/acceptance_test.go
@@ -135,7 +135,7 @@ func TestUpgrade(t *testing.T) {
 func TestRPMCompression(t *testing.T) {
 	t.Parallel()
 	format := "rpm"
-	compressFormats := []string{"gzip", "xz", "lzma"}
+	compressFormats := []string{"gzip", "xz", "lzma", "zstd"}
 	for _, arch := range formatArchs[format] {
 		for _, compFormat := range compressFormats {
 			func(t *testing.T, testCompFormat, testArch string) {
@@ -164,7 +164,7 @@ func TestRPMCompression(t *testing.T) {
 func TestDebCompression(t *testing.T) {
 	t.Parallel()
 	format := "deb"
-	compressFormats := []string{"gzip", "xz", "none"}
+	compressFormats := []string{"gzip", "xz", "zstd", "none"}
 	for _, arch := range formatArchs[format] {
 		for _, compFormat := range compressFormats {
 			func(t *testing.T, testCompFormat, testArch string) {
@@ -173,13 +173,20 @@ func TestDebCompression(t *testing.T) {
 					if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
 						t.Skip("ppc64le arch not supported in pipeline")
 					}
+
+					target := "compression"
+					if testCompFormat == "zstd" {
+						// we can remove this exception as soon as the debian image supports zstd
+						target = "zstdcompression"
+					}
+
 					accept(t, acceptParms{
 						Name:   fmt.Sprintf("%s_compression_%s", testCompFormat, testArch),
 						Conf:   fmt.Sprintf("deb.%s.compression.yaml", testCompFormat),
 						Format: format,
 						Docker: dockerParams{
 							File:   fmt.Sprintf("%s.dockerfile", format),
-							Target: "compression",
+							Target: target,
 							Arch:   testArch,
 						},
 					})
diff --git a/deb/deb_test.go b/deb/deb_test.go
index af808ad..19b209d 100644
--- a/deb/deb_test.go
+++ b/deb/deb_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/goreleaser/nfpm/v2"
 	"github.com/goreleaser/nfpm/v2/files"
 	"github.com/goreleaser/nfpm/v2/internal/sign"
+	"github.com/klauspost/compress/zstd"
 	"github.com/stretchr/testify/require"
 	"github.com/xi2/xz"
 )
@@ -1080,6 +1081,7 @@ func TestCompressionAlgorithms(t *testing.T) {
 		{"", "data.tar.gz"}, // test current default
 		{"xz", "data.tar.xz"},
 		{"none", "data.tar"},
+		{"zstd", "data.tar.zst"},
 	}
 
 	for _, testCase := range testCases {
@@ -1237,6 +1239,10 @@ func inflate(tb testing.TB, nameOrType string, data []byte) []byte {
 		r, err := xz.NewReader(dataReader, 0)
 		require.NoError(tb, err)
 		inflateReadCloser = io.NopCloser(r)
+	case "zst":
+		r, err := zstd.NewReader(dataReader)
+		require.NoError(tb, err)
+		inflateReadCloser = &zstdReadCloser{r}
 	case "tar", "": // no compression
 		inflateReadCloser = io.NopCloser(dataReader)
 	default:
@@ -1413,3 +1419,13 @@ func TestBadProvides(t *testing.T) {
 	require.NoError(t, err)
 	require.Equal(t, string(bts), w.String())
 }
+
+type zstdReadCloser struct {
+	*zstd.Decoder
+}
+
+func (zrc *zstdReadCloser) Close() error {
+	zrc.Decoder.Close()
+
+	return nil
+}
diff --git a/testdata/acceptance/deb.dockerfile b/testdata/acceptance/deb.dockerfile
index 3bfa657..9c470b9 100644
--- a/testdata/acceptance/deb.dockerfile
+++ b/testdata/acceptance/deb.dockerfile
@@ -173,6 +173,20 @@ RUN echo wat >> /etc/foo/whatever.conf
 RUN dpkg -r foo
 RUN test ! -f /usr/bin/fake
 
+# ---- zstdcompression test ----
+# we can use the regular compression image as
+# soon as zstd is supported on debian
+FROM ubuntu AS zstdcompression
+ARG package
+RUN echo "${package}"
+COPY ${package} /tmp/foo.deb
+RUN dpkg -i /tmp/foo.deb
+RUN test -e /usr/bin/fake
+RUN test -f /etc/foo/whatever.conf
+RUN echo wat >> /etc/foo/whatever.conf
+RUN dpkg -r foo
+RUN test ! -f /usr/bin/fake
+
 # ---- upgrade test ----
 FROM test_base AS upgrade
 ARG oldpackage
diff --git a/testdata/acceptance/deb.zstd.compression.yaml b/testdata/acceptance/deb.zstd.compression.yaml
new file mode 100644
index 0000000..9dd7d73
--- /dev/null
+++ b/testdata/acceptance/deb.zstd.compression.yaml
@@ -0,0 +1,19 @@
+name: "foo"
+arch: "${BUILD_ARCH}"
+platform: "linux"
+version: "v1.2.3"
+maintainer: "Foo Bar"
+description: |
+  Foo bar
+    Multiple lines
+vendor: "foobar"
+homepage: "https://foobar.org"
+license: "MIT"
+contents:
+  - src: ./testdata/fake
+    dst: /usr/bin/fake
+  - src: ./testdata/whatever.conf
+    dst: /etc/foo/whatever.conf
+    type: config
+deb:
+  compression: "zstd"
diff --git a/testdata/acceptance/rpm.zstd.compression.yaml b/testdata/acceptance/rpm.zstd.compression.yaml
new file mode 100644
index 0000000..7430821
--- /dev/null
+++ b/testdata/acceptance/rpm.zstd.compression.yaml
@@ -0,0 +1,19 @@
+name: "foo"
+arch: "${BUILD_ARCH}"
+platform: "linux"
+version: "v1.2.3"
+maintainer: "Foo Bar"
+description: |
+  Foo bar
+    Multiple lines
+vendor: "foobar"
+homepage: "https://foobar.org"
+license: "MIT"
+contents:
+- src: ./testdata/fake
+  dst: /usr/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
+rpm:
+  compression: "zstd"