Repository: goreleaser/nfpm
Pull request #158 (2020-07-09 12:52:32)

feat(#42): Support Changelogs
This pull request adds the ability to add a changelog by specifying a [](https://github.com/goreleaser/chglog) compatible YAML file in the configuration file. This pull request was built based on the [djgilcrease's great pull request #105](https://github.com/goreleaser/nfpm/pull/105), however, the following changes were made:
* All properties of the changelog are entirely defined by the changelog YAML file. No default changelog entry is created and no information is sourced from `Info`. `nfpm` should not manage the changelog. Instead, it should only provide the means to add your own changelog to a package.
* If no changelog YAML file is specified, nothing changelog-related is added to the package for users that explicitly do not want a changelog.
* Dependency from specifc pull request branch of the `rpmpack` repos was removed. This was necessary because the pull request was closed. A different API for the same purpose was added since, so I used this API.
* The nomenclature for the configuration file was change from `chglog` to `changelog` to be more clear for a better user experience.
* The pull request is compatible with `master` again.
* I did not add any changelog information for the `nfpm` package itself, because this pull request only concerns the feature support and maintenance of the `nfpm` package itself is kind of orthogonal to that.

vercel[bot]: 
This pull request is being automatically deployed with Vercel ([learn more](https://vercel.link/github-learn-more)).
To see the status of your deployment, click on the icon next to each commit.
	
erikgeiser: Hmm, `go generate -v .` produces the following error:
```
# github.com/golangci/golangci-lint/pkg/golinters
../go/pkg/mod/github.com/golangci/golangci-lint@v1.28.1/pkg/golinters/gofumpt.go:49:41: cannot use "" (type string) as type format.Options in argument to format.Source
nfpm.go:1: running "go": exit status 2
```
As far as I can see, compared to `master`, this regression was introduced by adding the dependency https://github.com/goreleaser/chglog. I have no idea why. I could also easily get rid of the dependency. All I really need are the structures to unmarshal YAML and the deb template. What do you think?
erikgeiser: I added in depth tests for the `./deb` and `./rpm` packages as well as acceptance tests for both formats. I also updated the documentation. From my side, this is now ready to be merged.
caarlos0: I'll review it later today or over the weekend, thanks for the PR meanwhile :) 
erikgeiser: I just notices that I most of my commits with a wrong mail address. Would it be okay to squash all these messy commits into a single correct one and force push?
caarlos0: > I just notices that I accidentally sent most of my commits with the wrong mail address. Would it be okay to squash all these messy commits into a single correct one and force push?

yes, no problem :) 
caarlos0: Also would be nice to include @djgilcrease as co-author
djgilcrease: Thank you very much, I got pulled to a new project at work that has kept me too busy to get back to this. This looks great.
erikgeiser: I cleaned up my commits.

> Also would be nice to include @djgilcrease as co-author

How can I do this, or is this something that's done when merging into master? I already tried to give credit in the commit message and in the description above, but being a co-author is obviously nicer.
djgilcrease: > How can I do this, or is this something that's done when merging into master? I already tried to give credit in the commit message and in the description above, but being a co-author is obviously nicer.

He just wanted me to take a look and ensure the direction is still where I wanted to go with it. I like the changes you made to have it so nfpm only uses the file if it is there but leaves the generation and management up to the chglog tool. If we want tighter integration in the future we can add config option to enable auto generation of changelog.
erikgeiser: > I like the changes you made to have it so nfpm only uses the file if it is there but leaves the generation and management up to the chglog tool. If we want tighter integration in the future we can add config option to enable auto generation of changelog.

I did this because I envision `nfpm` to be tailor-made tool precisely to craft package files. In my opinion, changelogs are mostly orthogonal to that idea other than the fact that the package formats require special integration of changelog files. That's why I think `nfpm` should not manage changelogs but only provides means to include them in package formats correctly.

But maybe my point of view is a bit biased because I primarily use `nfpm` wrapped by out own custom build system tailored to out needs such that `nfpm` is simple the "assembly tool" for package files.
djgilcrease: > But maybe my point of view is a bit biased because I primarily use `nfpm` wrapped by out own custom build system tailored to out needs such that `nfpm` is simple the "assembly tool" for package files. This strategy would also help to keep it from getting as bloated as `fpm`.

This is how I actually use it as well, just a stage in the pipeline to package things to be pushed up to an internal artifactory server.
caarlos0: > How can I do this, or is this something that's done when merging into master?

when you rebase the commits, just add 

```
Co-authored-by: another-name <another-name@example.com>"
```

to the end of the commit message https://docs.github.com/en/enterprise/2.13/user/articles/creating-a-commit-with-multiple-authors 
erikgeiser: > when you rebase the commits, just add to the end of the commit message :)

Just for my curiousity: I did `git rebase master; git commit --amend` and then had to force push again. Is there a better way to do this?
caarlos0: > Just for my curiousity: I did `git rebase master; git commit --amend` and then had to force push again. Is there a better way to do this?

AFAIK that's it...

Patch:
diff --git a/cmd/nfpm/main.go b/cmd/nfpm/main.go
index 792bc97..4f5bb8d 100644
--- a/cmd/nfpm/main.go
+++ b/cmd/nfpm/main.go
@@ -148,6 +148,7 @@ description: |
 vendor: "FooBarCorp"
 homepage: "http://example.com"
 license: "MIT"
+changelog: "changelog.yaml"
 files:
   ./foo: "/usr/local/bin/foo"
   ./bar: "/usr/local/bin/bar"
diff --git a/deb/deb.go b/deb/deb.go
index a6abd47..542b284 100644
--- a/deb/deb.go
+++ b/deb/deb.go
@@ -18,6 +18,8 @@ import (
 	"github.com/blakesmith/ar"
 	"github.com/pkg/errors"
 
+	"github.com/goreleaser/chglog"
+
 	"github.com/goreleaser/nfpm"
 )
 
@@ -140,15 +142,42 @@ func createFilesInsideTarGz(info *nfpm.Info, out *tar.Writer, created map[string
 		return md5buf, 0, err
 	}
 	for _, file := range files {
-		if err := createTree(out, file.Destination, created); err != nil {
+		if err = createTree(out, file.Destination, created); err != nil {
 			return md5buf, 0, err
 		}
-		size, err := copyToTarAndDigest(out, &md5buf, file.Source, file.Destination)
+
+		var size int64 // declare early to avoid shadowing err
+		size, err = copyToTarAndDigest(out, &md5buf, file.Source, file.Destination)
 		if err != nil {
 			return md5buf, 0, err
 		}
 		instSize += size
 	}
+
+	if info.Changelog != "" {
+		changelog, err := createChangelog(info)
+		if err != nil {
+			return md5buf, 0, err
+		}
+
+		// https://www.debian.org/doc/manuals/developers-reference/pkgs.de.html#recording-changes-in-the-package
+		changelogName := fmt.Sprintf("/usr/share/doc/%s/changelog.gz", info.Name)
+		if err = createTree(out, changelogName, created); err != nil {
+			return md5buf, 0, err
+		}
+
+		var digest = md5.New() // nolint:gas
+		if _, err = fmt.Fprintf(&md5buf, "%x  %s\n", digest.Sum(nil), changelog); err != nil {
+			return md5buf, instSize, err
+		}
+
+		if err = newFileInsideTarGz(out, changelogName, changelog); err != nil {
+			return md5buf, instSize, err
+		}
+
+		instSize += int64(len(changelog))
+	}
+
 	return md5buf, instSize, nil
 }
 
@@ -199,6 +228,48 @@ func copyToTarAndDigest(tarw *tar.Writer, md5w io.Writer, src, dst string) (int6
 	return info.Size(), nil
 }
 
+func createChangelog(info *nfpm.Info) (chglogTarGz []byte, err error) {
+	var buf bytes.Buffer
+	var out = gzip.NewWriter(&buf)
+	// the writers are properly closed later, this is just in case that we have
+	// an error in another part of the code.
+	defer out.Close() // nolint: errcheck
+
+	chglogData, err := formatChangelog(info)
+	if err != nil {
+		return nil, err
+	}
+
+	if _, err = out.Write([]byte(chglogData)); err != nil {
+		return nil, err
+	}
+
+	if err := out.Close(); err != nil {
+		return nil, errors.Wrap(err, "closing changelog.gz")
+	}
+
+	return buf.Bytes(), nil
+}
+
+func formatChangelog(info *nfpm.Info) (string, error) {
+	pkgChglog, err := info.GetChangeLog()
+	if err != nil {
+		return "", err
+	}
+
+	tpl, err := chglog.DebTemplate()
+	if err != nil {
+		return "", err
+	}
+
+	chglogData, err := chglog.FormatChangelog(pkgChglog, tpl)
+	if err != nil {
+		return "", err
+	}
+
+	return chglogData, nil
+}
+
 func createControl(instSize int64, md5sums []byte, info *nfpm.Info) (controlTarGz []byte, err error) {
 	var buf bytes.Buffer
 	var compress = gzip.NewWriter(&buf)
@@ -209,18 +280,29 @@ func createControl(instSize int64, md5sums []byte, info *nfpm.Info) (controlTarG
 	defer compress.Close() // nolint: errcheck
 
 	var body bytes.Buffer
-	if err := writeControl(&body, controlData{
+	if err = writeControl(&body, controlData{
 		Info:          info,
 		InstalledSize: instSize / 1024,
 	}); err != nil {
 		return nil, err
 	}
 
-	for name, content := range map[string][]byte{
+	filesToCreate := map[string][]byte{
 		"control":   body.Bytes(),
 		"md5sums":   md5sums,
 		"conffiles": conffiles(info),
-	} {
+	}
+
+	if info.Changelog != "" {
+		changeLogData, err := formatChangelog(info)
+		if err != nil {
+			return nil, err
+		}
+
+		filesToCreate["changelog"] = []byte(changeLogData)
+	}
+
+	for name, content := range filesToCreate {
 		if err := newFileInsideTarGz(out, name, content); err != nil {
 			return nil, err
 		}
diff --git a/go.mod b/go.mod
index 5842830..7281987 100644
--- a/go.mod
+++ b/go.mod
@@ -10,6 +10,7 @@ require (
 	github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
 	github.com/golangci/golangci-lint v1.28.3
 	github.com/google/rpmpack v0.0.0-20200711065858-671dbb9d0be5
+	github.com/goreleaser/chglog v0.0.0-20191115023842-d969fbb05c3c
 	github.com/imdario/mergo v0.3.9
 	github.com/mattn/go-zglob v0.0.2
 	github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
diff --git a/go.sum b/go.sum
index e182439..4b05c3b 100644
--- a/go.sum
+++ b/go.sum
@@ -16,14 +16,21 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5 h1:XTrzB+F8+SpRmbhAH8HLxhiiG6nYNwaBZjrFps1oWEk=
 github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
+github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
+github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
 github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
 github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/semver/v3 v3.0.2/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
 github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk=
 github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
+github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
 github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
 github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
+github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
 github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
 github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -32,10 +39,14 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
@@ -51,11 +62,14 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -64,12 +78,18 @@ github.com/denis-tingajkin/go-header v0.3.1 h1:ymEpSiFjeItCy1FOP+x0M2KdCELdEAHUs
 github.com/denis-tingajkin/go-header v0.3.1/go.mod h1:sq/2IxMhaZX+RRcgHfCRx/m0M5na0fBt4/CRe7Lrji0=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
+github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-critic/go-critic v0.5.0 h1:Ic2p5UCl5fX/2WX2w8nroPpPhxRNsNTMlJzsu/uqwnM=
 github.com/go-critic/go-critic v0.5.0/go.mod h1:4jeRh3ZAVnRYhuWdOEvwzVqLUpxMSoAT0xZ74JsTPlo=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -164,11 +184,15 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
 github.com/google/rpmpack v0.0.0-20200711065858-671dbb9d0be5 h1:7P5uYhwxBFsVZrkPmon2EIhFICvv3ughhTg99yphzLQ=
 github.com/google/rpmpack v0.0.0-20200711065858-671dbb9d0be5/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/goreleaser/chglog v0.0.0-20191115023842-d969fbb05c3c h1:XYmQbm4YuLFQLBlaToxLmhtmzlhQV77jFglvSstQboo=
+github.com/goreleaser/chglog v0.0.0-20191115023842-d969fbb05c3c/go.mod h1:DpqL5/zceatNHQW0lbGenIAwNJGfmCY0pBH43zDkxpQ=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
@@ -200,10 +224,16 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
+github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
 github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk=
 github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s=
 github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3 h1:jNYPNLe3d8smommaoQlK7LOA5ESyUJJ+Wf79ZtA7Vp4=
@@ -216,6 +246,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
+github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -227,6 +259,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@@ -257,6 +290,8 @@ github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpe
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -267,6 +302,9 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
+github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
@@ -290,8 +328,10 @@ github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0C
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
+github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
+github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
 github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA=
 github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -318,6 +358,7 @@ github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:r
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryancurrah/gomodguard v1.1.0 h1:DWbye9KyMgytn8uYpuHkwf0RHqAYO6Ay/D0TbCpPtVU=
 github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM=
@@ -329,6 +370,8 @@ github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/securego/gosec/v2 v2.3.0 h1:y/9mCF2WPDbSDpL3QDWZD3HHGrSYw0QSHnCqTfs4JPE=
 github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME=
+github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
 github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
 github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM=
@@ -349,23 +392,31 @@ github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4l
 github.com/sourcegraph/go-diff v0.5.3 h1:lhIKJ2nXLZZ+AfbHpYxTn0pXpNTTui0DX7DO3xeb1Zs=
 github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4=
 github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
 github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
+github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -384,6 +435,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1
 github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa h1:RC4maTWLKKwb7p1cnoygsbKIgNlJqSYBeAFON3Ar8As=
 github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
 github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
 github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
@@ -397,6 +449,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
 github.com/valyala/fasthttp v1.12.0/go.mod h1:229t1eWu9UXTPmoUkbpN/fctKPBY4IJoFXQnxHGXy6E=
 github.com/valyala/quicktemplate v1.5.0/go.mod h1:v7yYWpBEiutDyNfVaph6oC/yKwejzVyTX/2cwwHxyok=
 github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
+github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
+github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@@ -411,9 +465,12 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -454,6 +511,7 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@@ -473,7 +531,9 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -482,6 +542,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -515,6 +576,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
+golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -572,12 +634,21 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
 gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
+gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
+gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
+gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
+gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
+gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/nfpm.go b/nfpm.go
index 2f21cf8..f67db71 100644
--- a/nfpm.go
+++ b/nfpm.go
@@ -16,6 +16,8 @@ import (
 	"github.com/imdario/mergo"
 	"github.com/pkg/errors"
 
+	"github.com/goreleaser/chglog"
+
 	"github.com/goreleaser/nfpm/glob"
 	"github.com/goreleaser/nfpm/internal/helpers"
 
@@ -137,6 +139,7 @@ type Info struct {
 	Homepage     string `yaml:"homepage,omitempty"`
 	License      string `yaml:"license,omitempty"`
 	Bindir       string `yaml:"bindir,omitempty"` // Deprecated: this does nothing. TODO: remove.
+	Changelog    string `yaml:"changelog,omitempty"`
 	Target       string `yaml:"-"`
 }
 
@@ -269,3 +272,22 @@ func (info *Info) FilesToCopy() ([]FileToCopy, error) {
 	})
 	return files, nil
 }
+
+// GetChangeLog parses the provided changelog file.
+func (info *Info) GetChangeLog() (log *chglog.PackageChangeLog, err error) {
+	// if the file does not exist chglog.Parse will just silently
+	// create an empty changelog but we should notify the user instead
+	if _, err = os.Stat(info.Changelog); os.IsNotExist(err) {
+		return nil, err
+	}
+
+	entries, err := chglog.Parse(info.Changelog)
+	if err != nil {
+		return nil, err
+	}
+
+	return &chglog.PackageChangeLog{
+		Name:    info.Name,
+		Entries: entries,
+	}, nil
+}
diff --git a/rpm/rpm.go b/rpm/rpm.go
index c91b96e..7b92441 100644
--- a/rpm/rpm.go
+++ b/rpm/rpm.go
@@ -3,6 +3,7 @@
 package rpm
 
 import (
+	"bytes"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -14,9 +15,27 @@ import (
 	"github.com/google/rpmpack"
 	"github.com/pkg/errors"
 
+	"github.com/goreleaser/chglog"
+
 	"github.com/goreleaser/nfpm"
 )
 
+const (
+	// https://github.com/rpm-software-management/rpm/blob/master/lib/rpmtag.h#L152
+	tagChangelogTime = 1080
+	// https://github.com/rpm-software-management/rpm/blob/master/lib/rpmtag.h#L153
+	tagChangelogName = 1081
+	// https://github.com/rpm-software-management/rpm/blob/master/lib/rpmtag.h#L154
+	tagChangelogText = 1082
+
+	changelogNotesTemplate = `
+	{{- range .Changes }}{{$note := splitList "\n" .Note}}
+	- {{ first $note }}
+	{{- range $i,$n := (rest $note) }}{{- if ne (trim $n) ""}}
+	{{$n}}{{end}}
+	{{- end}}{{- end}}`
+)
+
 // nolint: gochecknoinits
 func init() {
 	nfpm.Register("rpm", Default)
@@ -79,6 +98,12 @@ func (*RPM) Package(info *nfpm.Info, w io.Writer) error {
 		return err
 	}
 
+	if info.Changelog != "" {
+		if err = addChangeLog(info, rpm); err != nil {
+			return err
+		}
+	}
+
 	if err = rpm.Write(w); err != nil {
 		return err
 	}
@@ -86,6 +111,46 @@ func (*RPM) Package(info *nfpm.Info, w io.Writer) error {
 	return nil
 }
 
+func addChangeLog(info *nfpm.Info, rpm *rpmpack.RPM) error {
+	changelog, err := info.GetChangeLog()
+	if err != nil {
+		return fmt.Errorf("reading changelog: %w", err)
+	}
+
+	if len(changelog.Entries) == 0 {
+		// no nothing because creating empty tags
+		// would result in an invalid package
+		return nil
+	}
+
+	tpl, err := chglog.LoadTemplateData(changelogNotesTemplate)
+	if err != nil {
+		return fmt.Errorf("parsing RPM changelog template: %w", err)
+	}
+
+	changes := make([]string, len(changelog.Entries))
+	titles := make([]string, len(changelog.Entries))
+	times := make([]uint32, len(changelog.Entries))
+	for idx, entry := range changelog.Entries {
+		var formattedNotes bytes.Buffer
+
+		err := tpl.Execute(&formattedNotes, entry)
+		if err != nil {
+			return fmt.Errorf("formatting changlog notes: %w", err)
+		}
+
+		changes[idx] = strings.TrimSpace(formattedNotes.String())
+		times[idx] = uint32(entry.Date.Unix())
+		titles[idx] = fmt.Sprintf("%s - %s", entry.Packager, entry.Semver)
+	}
+
+	rpm.AddCustomTag(tagChangelogTime, rpmpack.EntryUint32(times))
+	rpm.AddCustomTag(tagChangelogName, rpmpack.EntryStringSlice(titles))
+	rpm.AddCustomTag(tagChangelogText, rpmpack.EntryStringSlice(changes))
+
+	return nil
+}
+
 //nolint:funlen
 func buildRPMMeta(info *nfpm.Info) (*rpmpack.RPMMetaData, error) {
 	var (
diff --git a/www/docs/configuration.md b/www/docs/configuration.md
index 3e49344..850f65b 100644
--- a/www/docs/configuration.md
+++ b/www/docs/configuration.md
@@ -52,6 +52,9 @@ homepage: https://nfpm.goreleaser.com
 # License.
 license: MIT
 
+# Changelog YAML file, see: https://github.com/goreleaser/chglog
+changelog: "changelog.yaml"
+
 # Packages it replaces. (overridable)
 replaces:
 - foobar


Test patch:
diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go
index 7d3f2c9..ebc4e76 100644
--- a/acceptance/acceptance_test.go
+++ b/acceptance/acceptance_test.go
@@ -181,6 +181,21 @@ func TestDebRules(t *testing.T) {
 	})
 }
 
+func TestChangelog(t *testing.T) {
+	for _, format := range formats {
+		format := format
+		t.Run(fmt.Sprintf("changelog-%s", format), func(t *testing.T) {
+			t.Parallel()
+			accept(t, acceptParms{
+				Name:       fmt.Sprintf("changelog_%s", format),
+				Conf:       "withchangelog.yaml",
+				Format:     format,
+				Dockerfile: fmt.Sprintf("%s.changelog.dockerfile", format),
+			})
+		})
+	}
+}
+
 type acceptParms struct {
 	Name       string
 	Conf       string
diff --git a/acceptance/testdata/deb.changelog.dockerfile b/acceptance/testdata/deb.changelog.dockerfile
new file mode 100644
index 0000000..535d234
--- /dev/null
+++ b/acceptance/testdata/deb.changelog.dockerfile
@@ -0,0 +1,11 @@
+FROM ubuntu
+ARG package
+COPY ${package} /tmp/foo.deb
+RUN apt upgrade -y
+RUN apt install -y gzip
+RUN dpkg -i /tmp/foo.deb
+RUN zcat "/usr/share/doc/foo/changelog.gz" | grep "Carlos A Becker <pkg@carlosbecker.com>"
+RUN zcat "/usr/share/doc/foo/changelog.gz" | grep "note 1"
+RUN zcat "/usr/share/doc/foo/changelog.gz" | grep "note 2"
+RUN zcat "/usr/share/doc/foo/changelog.gz" | grep "note 3"
+RUN dpkg -r foo
diff --git a/acceptance/testdata/rpm.changelog.dockerfile b/acceptance/testdata/rpm.changelog.dockerfile
new file mode 100644
index 0000000..9bf4721
--- /dev/null
+++ b/acceptance/testdata/rpm.changelog.dockerfile
@@ -0,0 +1,13 @@
+FROM fedora
+ARG package
+COPY ${package} /tmp/foo.rpm
+RUN rpm -ivh /tmp/foo.rpm
+RUN rpm -qp /tmp/foo.rpm --changelog | grep "Carlos A Becker <pkg@carlosbecker.com>"
+RUN rpm -qp /tmp/foo.rpm --changelog | grep "note 1"
+RUN rpm -qp /tmp/foo.rpm --changelog | grep "note 2"
+RUN rpm -qp /tmp/foo.rpm --changelog | grep "note 3"
+RUN rpm -q foo --changelog | grep "Carlos A Becker <pkg@carlosbecker.com>"
+RUN rpm -q foo --changelog | grep "note 1"
+RUN rpm -q foo --changelog | grep "note 2"
+RUN rpm -q foo --changelog | grep "note 3"
+RUN rpm -e foo
diff --git a/acceptance/testdata/withchangelog.yaml b/acceptance/testdata/withchangelog.yaml
new file mode 100644
index 0000000..7d70f9b
--- /dev/null
+++ b/acceptance/testdata/withchangelog.yaml
@@ -0,0 +1,17 @@
+name: "foo"
+arch: "amd64"
+platform: "linux"
+changelog: "../testdata/changelog.yaml"
+version: "v1.2.3"
+release: "simple"
+maintainer: "Foo Bar"
+description: |
+  Foo bar
+    Multiple lines
+vendor: "foobar"
+homepage: "https://foobar.org"
+license: "MIT"
+files:
+  ../testdata/fake: "/usr/local/bin/fake"
+config_files:
+  ../testdata/whatever.conf: "/etc/foo/whatever.conf"
diff --git a/deb/deb_test.go b/deb/deb_test.go
index efe7ee1..837e39b 100644
--- a/deb/deb_test.go
+++ b/deb/deb_test.go
@@ -3,9 +3,12 @@ package deb
 import (
 	"archive/tar"
 	"bytes"
+	"compress/gzip"
 	"flag"
 	"fmt"
+	"io"
 	"io/ioutil"
+	"os"
 	"strconv"
 	"strings"
 	"testing"
@@ -13,6 +16,8 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
+	"github.com/goreleaser/chglog"
+
 	"github.com/goreleaser/nfpm"
 )
 
@@ -380,3 +385,151 @@ func TestMultilineFields(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, string(bts), w.String())
 }
+
+func TestDebChangelogControl(t *testing.T) {
+	info := &nfpm.Info{
+		Name:        "changelog-test",
+		Arch:        "amd64",
+		Description: "This package has changelogs.",
+		Version:     "1.0.0",
+		Changelog:   "../testdata/changelog.yaml",
+	}
+
+	controlTarGz, err := createControl(0, []byte{}, info)
+	assert.NoError(t, err)
+
+	controlChangelog, err := extractFileFromTarGz(controlTarGz, "changelog")
+	assert.NoError(t, err)
+
+	goldenChangelog, err := readAndFormatAsDebChangelog(info.Changelog, info.Name)
+	assert.NoError(t, err)
+
+	assert.Equal(t, goldenChangelog, string(controlChangelog))
+}
+
+func TestDebNoChangelogControlWithoutChangelogConfigured(t *testing.T) {
+	info := &nfpm.Info{
+		Name:        "no-changelog-test",
+		Arch:        "amd64",
+		Description: "This package has explicitly no changelog.",
+		Version:     "1.0.0",
+	}
+
+	controlTarGz, err := createControl(0, []byte{}, info)
+	assert.NoError(t, err)
+
+	_, err = extractFileFromTarGz(controlTarGz, "changelog")
+	assert.EqualError(t, err, os.ErrNotExist.Error())
+}
+
+func TestDebChangelogData(t *testing.T) {
+	info := &nfpm.Info{
+		Name:        "changelog-test",
+		Arch:        "amd64",
+		Description: "This package has changelogs.",
+		Version:     "1.0.0",
+		Changelog:   "../testdata/changelog.yaml",
+	}
+
+	dataTarGz, _, _, err := createDataTarGz(info)
+	assert.NoError(t, err)
+
+	changelogName := fmt.Sprintf("/usr/share/doc/%s/changelog.gz", info.Name)
+	dataChangelogGz, err := extractFileFromTarGz(dataTarGz, changelogName)
+	assert.NoError(t, err)
+
+	dataChangelog, err := gzipInflate(dataChangelogGz)
+	assert.NoError(t, err)
+
+	goldenChangelog, err := readAndFormatAsDebChangelog(info.Changelog, info.Name)
+	assert.NoError(t, err)
+
+	assert.Equal(t, goldenChangelog, string(dataChangelog))
+}
+
+func TestDebNoChangelogDataWithoutChangelogConfigured(t *testing.T) {
+	info := &nfpm.Info{
+		Name:        "no-changelog-test",
+		Arch:        "amd64",
+		Description: "This package has explicitly no changelog.",
+		Version:     "1.0.0",
+	}
+
+	dataTarGz, _, _, err := createDataTarGz(info)
+	assert.NoError(t, err)
+
+	changelogName := fmt.Sprintf("/usr/share/doc/%s/changelog.gz", info.Name)
+	_, err = extractFileFromTarGz(dataTarGz, changelogName)
+	assert.EqualError(t, err, os.ErrNotExist.Error())
+}
+
+func extractFileFromTarGz(tarGzFile []byte, filename string) ([]byte, error) {
+	tarFile, err := gzipInflate(tarGzFile)
+	if err != nil {
+		return nil, err
+	}
+
+	tr := tar.NewReader(bytes.NewReader(tarFile))
+	for {
+		hdr, err := tr.Next()
+		if err == io.EOF {
+			break // End of archive
+		}
+		if err != nil {
+			return nil, err
+		}
+
+		if hdr.Name != filename {
+			continue
+		}
+
+		fileContents, err := ioutil.ReadAll(tr)
+		if err != nil {
+			return nil, err
+		}
+
+		return fileContents, nil
+	}
+
+	return nil, os.ErrNotExist
+}
+
+func gzipInflate(data []byte) ([]byte, error) {
+	gzr, err := gzip.NewReader(bytes.NewReader(data))
+	if err != nil {
+		return nil, err
+	}
+
+	inflatedData, err := ioutil.ReadAll(gzr)
+	if err != nil {
+		return nil, err
+	}
+
+	if err = gzr.Close(); err != nil {
+		return nil, err
+	}
+
+	return inflatedData, nil
+}
+
+func readAndFormatAsDebChangelog(changelogFileName, packageName string) (string, error) {
+	changelogEntries, err := chglog.Parse(changelogFileName)
+	if err != nil {
+		return "", err
+	}
+
+	tpl, err := chglog.DebTemplate()
+	if err != nil {
+		return "", err
+	}
+
+	debChangelog, err := chglog.FormatChangelog(&chglog.PackageChangeLog{
+		Name:    packageName,
+		Entries: changelogEntries,
+	}, tpl)
+	if err != nil {
+		return "", err
+	}
+
+	return debChangelog, nil
+}
diff --git a/rpm/rpm_test.go b/rpm/rpm_test.go
index 25585fd..1c8c94d 100644
--- a/rpm/rpm_test.go
+++ b/rpm/rpm_test.go
@@ -1,14 +1,19 @@
 package rpm
 
 import (
+	"bytes"
 	"fmt"
 	"io/ioutil"
 	"os"
+	"strings"
 	"testing"
+	"time"
 
 	"github.com/sassoftware/go-rpmutils"
 	"github.com/stretchr/testify/assert"
 
+	"github.com/goreleaser/chglog"
+
 	"github.com/goreleaser/nfpm"
 )
 
@@ -296,3 +301,71 @@ func TestRPMMultiArch(t *testing.T) {
 		assert.Equal(t, archToRPM[k], info.Arch)
 	}
 }
+
+func TestRPMChangelog(t *testing.T) {
+	info := exampleInfo()
+	info.Changelog = "../testdata/changelog.yaml"
+
+	var rpmFileBuffer bytes.Buffer
+	err := Default.Package(info, &rpmFileBuffer)
+	assert.NoError(t, err)
+
+	rpm, err := rpmutils.ReadRpm(bytes.NewReader(rpmFileBuffer.Bytes()))
+	assert.NoError(t, err)
+
+	changelog, err := chglog.Parse(info.Changelog)
+	assert.NoError(t, err)
+
+	_times, err := rpm.Header.Get(tagChangelogTime)
+	assert.NoError(t, err)
+	times, ok := _times.([]uint32)
+	assert.True(t, ok)
+	assert.Equal(t, len(changelog), len(times))
+
+	_titles, err := rpm.Header.Get(tagChangelogName)
+	assert.NoError(t, err)
+	titles, ok := _titles.([]string)
+	assert.True(t, ok)
+	assert.Equal(t, len(changelog), len(titles))
+
+	_notes, err := rpm.Header.Get(tagChangelogText)
+	assert.NoError(t, err)
+	allNotes, ok := _notes.([]string)
+	assert.True(t, ok)
+	assert.Equal(t, len(changelog), len(allNotes))
+
+	for i, entry := range changelog {
+		timestamp := time.Unix(int64(times[i]), 0).UTC()
+		title := titles[i]
+		notes := strings.Split(allNotes[i], "\n")
+
+		assert.Equal(t, entry.Date, timestamp)
+		assert.True(t, strings.Contains(title, entry.Packager))
+		assert.True(t, strings.Contains(title, entry.Semver))
+		assert.Equal(t, len(entry.Changes), len(notes))
+
+		for j, change := range entry.Changes {
+			assert.True(t, strings.Contains(notes[j], change.Note))
+		}
+	}
+}
+
+func TestRPMNoChangelogTagsWithoutChangelogConfigured(t *testing.T) {
+	info := exampleInfo()
+
+	var rpmFileBuffer bytes.Buffer
+	err := Default.Package(info, &rpmFileBuffer)
+	assert.NoError(t, err)
+
+	rpm, err := rpmutils.ReadRpm(bytes.NewReader(rpmFileBuffer.Bytes()))
+	assert.NoError(t, err)
+
+	_, err = rpm.Header.Get(tagChangelogTime)
+	assert.Error(t, err)
+
+	_, err = rpm.Header.Get(tagChangelogName)
+	assert.Error(t, err)
+
+	_, err = rpm.Header.Get(tagChangelogText)
+	assert.Error(t, err)
+}
diff --git a/testdata/changelog.yaml b/testdata/changelog.yaml
new file mode 100644
index 0000000..dd55eb0
--- /dev/null
+++ b/testdata/changelog.yaml
@@ -0,0 +1,16 @@
+- semver: "1.1.0-1"
+  date: "2009-12-08T22:00:00Z"
+  packager: "Carlos A Becker <pkg@carlosbecker.com>"
+  urgency: "low"
+  distribution: "stable"
+  changes:
+    - note: "note 1"
+    - note: "note 2"
+
+- semver: "1.0.0-1"
+  date: "2009-11-10T23:00:00Z"
+  packager: "Carlos A Becker <pkg@carlosbecker.com>"
+  urgency: "low"
+  distribution: "stable"
+  changes:
+    - note: "note 3"