1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-17 20:47:50 +02:00

fix: use git-archive under the hood (#3904)

This reverts back to using `git archive` for the source archives... but
will keep supporting extra files.

##### How it works:

Basically, we run `git archive` as before.
Then, we make a backup of the generated archive, and create a new one
copying by reading from the backup and writing into the new one.
Finally, we write the extra files to the new one as well.

This only happens if the configuration does have extra files, otherwise,
just the simple `git archive` will be run.

PS: we can't just append to the archive because weird tar format
paddings et al.

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
This commit is contained in:
Carlos Alexandro Becker 2023-04-07 22:53:15 -03:00 committed by GitHub
parent 57d3bdd965
commit 0eb3e7975c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 349 additions and 123 deletions

View File

@ -317,10 +317,6 @@ type EnhancedArchive struct {
func (d EnhancedArchive) Add(f config.File) error {
name := strings.ReplaceAll(filepath.Join(d.wrap, f.Destination), "\\", "/")
log.Debugf("adding file: %s as %s", f.Source, name)
if _, ok := d.files[f.Destination]; ok {
return fmt.Errorf("file %s already exists in the archive", f.Destination)
}
d.files[f.Destination] = name
ff := config.File{
Source: f.Source,
Destination: name,

View File

@ -5,6 +5,7 @@ import (
"testing"
"github.com/goreleaser/goreleaser/internal/testctx"
"github.com/goreleaser/goreleaser/internal/testlib"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/stretchr/testify/require"
)
@ -30,7 +31,7 @@ func TestMeta(t *testing.T) {
require.Equal(
t,
[]string{"testdata/a/a.txt", "testdata/a/b/a.txt", "testdata/a/b/c/d.txt"},
tarFiles(t, filepath.Join(dist, "foo.tar.gz")),
testlib.LsArchive(t, filepath.Join(dist, "foo.tar.gz"), "tar.gz"),
)
})

View File

@ -2,10 +2,10 @@ package archive
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"testing"
@ -235,7 +235,7 @@ func TestRunPipe(t *testing.T) {
"foo/bar/foobar/blah.txt",
expectBin,
},
tarFiles(t, filepath.Join(dist, name)),
testlib.LsArchive(t, filepath.Join(dist, name), "tar.gz"),
)
header := tarInfo(t, filepath.Join(dist, name), expectBin)
@ -252,7 +252,7 @@ func TestRunPipe(t *testing.T) {
"foo/bar/foobar/blah.txt",
expectBin + ".exe",
},
zipFiles(t, filepath.Join(dist, "foobar_0.0.1_windows_amd64.zip")),
testlib.LsArchive(t, filepath.Join(dist, "foobar_0.0.1_windows_amd64.zip"), "zip"),
)
}
})
@ -355,21 +355,6 @@ func TestRunPipeNoBinaries(t *testing.T) {
require.NoError(t, Pipe{}.Run(ctx))
}
func zipFiles(t *testing.T, path string) []string {
t.Helper()
f, err := os.Open(path)
require.NoError(t, err)
info, err := f.Stat()
require.NoError(t, err)
r, err := zip.NewReader(f, info.Size())
require.NoError(t, err)
paths := make([]string, len(r.File))
for i, zf := range r.File {
paths[i] = zf.Name
}
return paths
}
func tarInfo(t *testing.T, path, name string) *tar.Header {
t.Helper()
f, err := os.Open(path)
@ -391,27 +376,6 @@ func tarInfo(t *testing.T, path, name string) *tar.Header {
return nil
}
func tarFiles(t *testing.T, path string) []string {
t.Helper()
f, err := os.Open(path)
require.NoError(t, err)
defer f.Close()
gr, err := gzip.NewReader(f)
require.NoError(t, err)
defer gr.Close()
r := tar.NewReader(gr)
var paths []string
for {
next, err := r.Next()
if err == io.EOF {
break
}
require.NoError(t, err)
paths = append(paths, next.Name)
}
return paths
}
func TestRunPipeBinary(t *testing.T) {
folder := testlib.Mktmp(t)
dist := filepath.Join(folder, "dist")
@ -742,22 +706,11 @@ func TestRunPipeWrap(t *testing.T) {
require.Len(t, archives, 1)
require.Equal(t, "foo_macOS", artifact.ExtraOr(*archives[0], artifact.ExtraWrappedIn, ""))
// Check archive contents
f, err = os.Open(filepath.Join(dist, "foo.tar.gz"))
require.NoError(t, err)
defer func() { require.NoError(t, f.Close()) }()
gr, err := gzip.NewReader(f)
require.NoError(t, err)
defer func() { require.NoError(t, gr.Close()) }()
r := tar.NewReader(gr)
for _, n := range []string{"README.md", "mybin"} {
h, err := r.Next()
if err == io.EOF {
break
}
require.NoError(t, err)
require.Equal(t, filepath.Join("foo_macOS", n), h.Name)
}
require.ElementsMatch(
t,
[]string{"foo_macOS/README.md", "foo_macOS/mybin"},
testlib.LsArchive(t, filepath.Join(dist, "foo.tar.gz"), "tar.gz"),
)
}
func TestDefault(t *testing.T) {
@ -999,10 +952,10 @@ func TestDuplicateFilesInsideArchive(t *testing.T) {
Source: ff.Name(),
Destination: "foo",
}))
require.EqualError(t, a.Add(config.File{
require.ErrorIs(t, a.Add(config.File{
Source: ff.Name(),
Destination: "foo",
}), "file foo already exists in the archive")
}), fs.ErrExist)
}
func TestWrapInDirectory(t *testing.T) {
@ -1068,7 +1021,7 @@ func TestArchive_globbing(t *testing.T) {
})
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, append(expected, "foobin"), tarFiles(t, filepath.Join(dist, "foo.tar.gz")))
require.Equal(t, append(expected, "foobin"), testlib.LsArchive(t, filepath.Join(dist, "foo.tar.gz"), "tar.gz"))
}
t.Run("exact src file", func(t *testing.T) {

View File

@ -5,16 +5,15 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/caarlos0/log"
"github.com/goreleaser/goreleaser/internal/archivefiles"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/deprecate"
"github.com/goreleaser/goreleaser/internal/gio"
"github.com/goreleaser/goreleaser/internal/git"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/archive"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
)
@ -30,49 +29,70 @@ func (Pipe) Skip(ctx *context.Context) bool {
}
// Run the pipe.
func (Pipe) Run(ctx *context.Context) (err error) {
func (Pipe) Run(ctx *context.Context) error {
format := ctx.Config.Source.Format
if format != "zip" && format != "tar" && format != "tgz" && format != "tar.gz" {
return fmt.Errorf("invalid source archive format: %s", format)
}
name, err := tmpl.New(ctx).Apply(ctx.Config.Source.NameTemplate)
if err != nil {
return err
}
filename := name + "." + ctx.Config.Source.Format
filename := name + "." + format
path := filepath.Join(ctx.Config.Dist, filename)
log.WithField("file", filename).Info("creating source archive")
out, err := git.Run(ctx, "ls-files")
if err != nil {
return fmt.Errorf("could not list source files: %w", err)
args := []string{
"archive",
"-o", path,
}
prefix, err := tmpl.New(ctx).Apply(ctx.Config.Source.PrefixTemplate)
if err != nil {
prefix := ""
if ctx.Config.Source.PrefixTemplate != "" {
pt, err := tmpl.New(ctx).Apply(ctx.Config.Source.PrefixTemplate)
if err != nil {
return err
}
prefix = pt
args = append(args, "--prefix", prefix)
}
args = append(args, ctx.Git.FullCommit)
if _, err := git.Clean(git.Run(ctx, args...)); err != nil {
return err
}
af, err := os.Create(path)
if len(ctx.Config.Source.Files) == 0 {
return nil
}
oldPath := path + ".bkp"
if err := gio.Copy(path, oldPath); err != nil {
return fmt.Errorf("failed make a backup of %q: %w", path, err)
}
// i could spend a lot of time trying to figure out how to append to a tar,
// tgz and zip file... but... this seems easy enough :)
of, err := os.Open(oldPath)
if err != nil {
return fmt.Errorf("could not create archive: %w", err)
return fmt.Errorf("could not open %q: %w", oldPath, err)
}
defer of.Close()
af, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0o644)
if err != nil {
return fmt.Errorf("could not open archive: %w", err)
}
defer af.Close() //nolint:errcheck
arch, err := archive.New(af, ctx.Config.Source.Format)
arch, err := archive.Copying(of, af, format)
if err != nil {
return err
}
var ff []config.File
for _, f := range strings.Split(out, "\n") {
if strings.TrimSpace(f) == "" {
continue
}
ff = append(ff, config.File{
Source: f,
})
}
files, err := archivefiles.Eval(
tmpl.New(ctx),
ctx.Config.Source.RLCP,
append(ff, ctx.Config.Source.Files...),
ctx.Config.Source.Files,
)
if err != nil {
return err
@ -96,7 +116,7 @@ func (Pipe) Run(ctx *context.Context) (err error) {
Name: filename,
Path: path,
Extra: map[string]interface{}{
artifact.ExtraFormat: ctx.Config.Source.Format,
artifact.ExtraFormat: format,
},
})
return err

View File

@ -1,7 +1,6 @@
package sourcearchive
import (
"archive/zip"
"os"
"path/filepath"
"testing"
@ -21,13 +20,14 @@ func TestArchive(t *testing.T) {
require.NoError(t, os.Mkdir("dist", 0o744))
testlib.GitInit(t)
require.NoError(t, os.WriteFile("code.txt", []byte("not really code"), 0o655))
require.NoError(t, os.WriteFile("code.rb", []byte("not really code"), 0o655))
require.NoError(t, os.WriteFile("code.py", []byte("print 1"), 0o655))
require.NoError(t, os.WriteFile("README.md", []byte("# my dope fake project"), 0o655))
testlib.GitAdd(t)
testlib.GitCommit(t, "feat: first")
require.NoError(t, os.WriteFile("added-later.txt", []byte("this file was added later"), 0o655))
require.NoError(t, os.WriteFile("ignored.md", []byte("never added"), 0o655))
require.NoError(t, os.WriteFile("code.txt", []byte("not really code"), 0o655))
require.NoError(t, os.MkdirAll("subfolder", 0o755))
require.NoError(t, os.WriteFile("subfolder/file.md", []byte("a file within a folder, added later"), 0o655))
@ -67,17 +67,22 @@ func TestArchive(t *testing.T) {
require.NoError(t, err)
require.Greater(t, stat.Size(), int64(100))
if format != "zip" {
return
}
require.ElementsMatch(t, []string{
expected := []string{
"foo-1.0.0/",
"foo-1.0.0/README.md",
"foo-1.0.0/code.py",
"foo-1.0.0/code.rb",
"foo-1.0.0/code.txt",
"foo-1.0.0/added-later.txt",
"foo-1.0.0/subfolder/file.md",
}, lsZip(t, path))
}
// zips wont have the parent dir
if format == "zip" {
expected = expected[1:]
}
require.ElementsMatch(t, expected, testlib.LsArchive(t, path, format))
})
}
}
@ -93,7 +98,7 @@ func TestInvalidFormat(t *testing.T) {
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.EqualError(t, Pipe{}.Run(ctx), "invalid archive format: 7z")
require.EqualError(t, Pipe{}.Run(ctx), "invalid source archive format: 7z")
}
func TestDefault(t *testing.T) {
@ -112,6 +117,7 @@ func TestInvalidNameTemplate(t *testing.T) {
NameTemplate: "{{ .foo }-asdda",
},
})
require.NoError(t, Pipe{}.Default(ctx))
testlib.RequireTemplateError(t, Pipe{}.Run(ctx))
}
@ -175,20 +181,3 @@ func TestSkip(t *testing.T) {
func TestString(t *testing.T) {
require.NotEmpty(t, Pipe{}.String())
}
func lsZip(tb testing.TB, path string) []string {
tb.Helper()
stat, err := os.Stat(path)
require.NoError(tb, err)
f, err := os.Open(path)
require.NoError(tb, err)
z, err := zip.NewReader(f, stat.Size())
require.NoError(tb, err)
var paths []string
for _, zf := range z.File {
paths = append(paths, zf.Name)
}
return paths
}

View File

@ -0,0 +1,86 @@
package testlib
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"io"
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/ulikunitz/xz"
)
// LsArchive return the file list of a given archive in a given formatkj
func LsArchive(tb testing.TB, path, format string) []string {
tb.Helper()
f := openFile(tb, path)
switch format {
case "tar.gz", "tgz":
return doLsTar(openGzip(tb, f))
case "tar.xz", "txz":
return doLsTar(openXz(tb, f))
case "tar":
return doLsTar(f)
case "zip":
return lsZip(tb, f)
case "gz":
return []string{openGzip(tb, f).Header.Name}
default:
tb.Errorf("invalid format: %s", format)
return nil
}
}
func openGzip(tb testing.TB, r io.Reader) *gzip.Reader {
tb.Helper()
gz, err := gzip.NewReader(r)
require.NoError(tb, err)
return gz
}
func openXz(tb testing.TB, r io.Reader) *xz.Reader {
tb.Helper()
xz, err := xz.NewReader(r)
require.NoError(tb, err)
return xz
}
func lsZip(tb testing.TB, f *os.File) []string {
tb.Helper()
stat, err := f.Stat()
require.NoError(tb, err)
z, err := zip.NewReader(f, stat.Size())
require.NoError(tb, err)
var paths []string
for _, zf := range z.File {
paths = append(paths, zf.Name)
}
return paths
}
func doLsTar(f io.Reader) []string {
z := tar.NewReader(f)
var paths []string
for {
h, err := z.Next()
if h == nil || err == io.EOF {
break
}
if h.Format == tar.FormatPAX {
continue
}
paths = append(paths, h.Name)
}
return paths
}
func openFile(tb testing.TB, path string) *os.File {
tb.Helper()
f, err := os.Open(path)
require.NoError(tb, err)
return f
}

View File

@ -4,6 +4,7 @@ package archive
import (
"fmt"
"io"
"os"
"github.com/goreleaser/goreleaser/pkg/archive/gzip"
"github.com/goreleaser/goreleaser/pkg/archive/tar"
@ -35,3 +36,17 @@ func New(w io.Writer, format string) (Archive, error) {
}
return nil, fmt.Errorf("invalid archive format: %s", format)
}
// Copying copies the source archive into a new one, which can be appended at.
// Source needs to be in the specified format.
func Copying(r *os.File, w io.Writer, format string) (Archive, error) {
switch format {
case "tar.gz", "tgz":
return targz.Copying(r, w)
case "tar":
return tar.Copying(r, w)
case "zip":
return zip.Copying(r, w)
}
return nil, fmt.Errorf("invalid archive format: %s", format)
}

View File

@ -3,8 +3,10 @@ package archive
import (
"io"
"os"
"path/filepath"
"testing"
"github.com/goreleaser/goreleaser/internal/testlib"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/stretchr/testify/require"
)
@ -19,11 +21,11 @@ func TestArchive(t *testing.T) {
for _, format := range []string{"tar.gz", "zip", "gz", "tar.xz", "tar"} {
format := format
t.Run(format, func(t *testing.T) {
archive, err := New(io.Discard, format)
f1, err := os.Create(filepath.Join(t.TempDir(), "1.tar"))
require.NoError(t, err)
archive, err := New(f1, format)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, archive.Close())
})
require.NoError(t, archive.Add(config.File{
Source: empty.Name(),
Destination: "empty.txt",
@ -32,6 +34,31 @@ func TestArchive(t *testing.T) {
Source: empty.Name() + "_nope",
Destination: "dont.txt",
}))
require.NoError(t, archive.Close())
require.NoError(t, f1.Close())
if format == "tar.xz" || format == "gz" {
_, err := Copying(f1, io.Discard, format)
require.Error(t, err)
return
}
f1, err = os.Open(f1.Name())
require.NoError(t, err)
f2, err := os.Create(filepath.Join(t.TempDir(), "2.tar"))
require.NoError(t, err)
a, err := Copying(f1, f2, format)
require.NoError(t, err)
require.NoError(t, a.Add(config.File{
Source: empty.Name(),
Destination: "added_later.txt",
}))
require.NoError(t, a.Close())
require.NoError(t, f1.Close())
require.NoError(t, f2.Close())
require.Equal(t, []string{"empty.txt", "added_later.txt"}, testlib.LsArchive(t, f2.Name(), format))
})
}

View File

@ -5,6 +5,7 @@ import (
"archive/tar"
"fmt"
"io"
"io/fs"
"os"
"github.com/goreleaser/goreleaser/pkg/config"
@ -12,16 +13,39 @@ import (
// Archive as tar.
type Archive struct {
tw *tar.Writer
tw *tar.Writer
files map[string]bool
}
// New tar archive.
func New(target io.Writer) Archive {
return Archive{
tw: tar.NewWriter(target),
tw: tar.NewWriter(target),
files: map[string]bool{},
}
}
// Copying creates a new tar with the contents of the given tar.
func Copying(source io.Reader, target io.Writer) (Archive, error) {
w := New(target)
r := tar.NewReader(source)
for {
h, err := r.Next()
if err == io.EOF || h == nil {
break
}
w.files[h.Name] = true
if err := w.tw.WriteHeader(h); err != nil {
return w, err
}
if _, err := io.Copy(w.tw, r); err != nil {
return w, err
}
}
return w, nil
}
// Close all closeables.
func (a Archive) Close() error {
return a.tw.Close()
@ -29,6 +53,10 @@ func (a Archive) Close() error {
// Add file to the archive.
func (a Archive) Add(f config.File) error {
if _, ok := a.files[f.Destination]; ok {
return &fs.PathError{Err: fs.ErrExist, Path: f.Destination, Op: "add"}
}
a.files[f.Destination] = true
info, err := os.Lstat(f.Source) // #nosec
if err != nil {
return fmt.Errorf("%s: %w", f.Source, err)

View File

@ -9,6 +9,7 @@ import (
"testing"
"time"
"github.com/goreleaser/goreleaser/internal/testlib"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/stretchr/testify/require"
)
@ -58,6 +59,11 @@ func TestTarFile(t *testing.T) {
Destination: "link.txt",
}))
require.ErrorIs(t, archive.Add(config.File{
Source: "../testdata/regular.txt",
Destination: "link.txt",
}), fs.ErrExist)
require.NoError(t, archive.Close())
require.Error(t, archive.Add(config.File{
Source: "tar.go",
@ -158,3 +164,34 @@ func TestTarInvalidLink(t *testing.T) {
Destination: "badlink.txt",
}))
}
func TestCopying(t *testing.T) {
f1, err := os.Create(filepath.Join(t.TempDir(), "1.tar"))
require.NoError(t, err)
f2, err := os.Create(filepath.Join(t.TempDir(), "2.tar"))
require.NoError(t, err)
t1 := New(f1)
require.NoError(t, t1.Add(config.File{
Source: "../testdata/foo.txt",
Destination: "foo.txt",
}))
require.NoError(t, t1.Close())
require.NoError(t, f1.Close())
f1, err = os.Open(f1.Name())
require.NoError(t, err)
t2, err := Copying(f1, f2)
require.NoError(t, err)
require.NoError(t, t2.Add(config.File{
Source: "../testdata/sub1/executable",
Destination: "executable",
}))
require.NoError(t, t2.Close())
require.NoError(t, f2.Close())
require.NoError(t, f1.Close())
require.Equal(t, []string{"foo.txt"}, testlib.LsArchive(t, f1.Name(), "tar"))
require.Equal(t, []string{"foo.txt", "executable"}, testlib.LsArchive(t, f2.Name(), "tar"))
}

View File

@ -27,6 +27,20 @@ func New(target io.Writer) Archive {
}
}
func Copying(source io.Reader, target io.Writer) (Archive, error) {
// the error will be nil since the compression level is valid
gw, _ := gzip.NewWriterLevel(target, gzip.BestCompression)
srcgz, err := gzip.NewReader(source)
if err != nil {
return Archive{}, err
}
tw, err := tar.Copying(srcgz, gw)
return Archive{
gw: gw,
tw: &tw,
}, err
}
// Close all closeables.
func (a Archive) Close() error {
if err := a.tw.Close(); err != nil {

View File

@ -7,6 +7,7 @@ import (
"compress/flate"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
@ -15,7 +16,8 @@ import (
// Archive zip struct.
type Archive struct {
z *zip.Writer
z *zip.Writer
files map[string]bool
}
// New zip archive.
@ -25,10 +27,51 @@ func New(target io.Writer) Archive {
return flate.NewWriter(out, flate.BestCompression)
})
return Archive{
z: compressor,
z: compressor,
files: map[string]bool{},
}
}
// New zip archive.
func Copying(source *os.File, target io.Writer) (Archive, error) {
info, err := source.Stat()
if err != nil {
return Archive{}, err
}
r, err := zip.NewReader(source, info.Size())
if err != nil {
return Archive{}, err
}
w := New(target)
for _, zf := range r.File {
if zf.Mode().IsDir() {
continue
}
w.files[zf.Name] = true
hdr := zip.FileHeader{
Name: zf.Name,
UncompressedSize64: zf.UncompressedSize64,
UncompressedSize: zf.UncompressedSize,
CreatorVersion: zf.CreatorVersion,
ExternalAttrs: zf.ExternalAttrs,
}
ww, err := w.z.CreateHeader(&hdr)
if err != nil {
return Archive{}, fmt.Errorf("creating %q header in target: %w", zf.Name, err)
}
rr, err := zf.Open()
if err != nil {
return Archive{}, fmt.Errorf("opening %q from source: %w", zf.Name, err)
}
defer rr.Close()
if _, err = io.Copy(ww, rr); err != nil {
return Archive{}, fmt.Errorf("copy from %q source to target: %w", zf.Name, err)
}
_ = rr.Close()
}
return w, nil
}
// Close all closeables.
func (a Archive) Close() error {
return a.z.Close()
@ -36,6 +79,10 @@ func (a Archive) Close() error {
// Add a file to the zip archive.
func (a Archive) Add(f config.File) error {
if _, ok := a.files[f.Destination]; ok {
return &fs.PathError{Err: fs.ErrExist, Path: f.Destination, Op: "add"}
}
a.files[f.Destination] = true
info, err := os.Lstat(f.Source) // #nosec
if err != nil {
return err

View File

@ -59,6 +59,11 @@ func TestZipFile(t *testing.T) {
Destination: "link.txt",
}))
require.ErrorIs(t, archive.Add(config.File{
Source: "../testdata/regular.txt",
Destination: "link.txt",
}), fs.ErrExist)
require.NoError(t, archive.Close())
require.Error(t, archive.Add(config.File{
Source: "tar.go",

View File

@ -933,7 +933,7 @@ type Publisher struct {
// Source configuration.
type Source struct {
NameTemplate string `yaml:"name_template,omitempty" json:"name_template,omitempty"`
Format string `yaml:"format,omitempty" json:"format,omitempty"`
Format string `yaml:"format,omitempty" json:"format,omitempty" jsonschema:"enum=tar,enum=tgz,enum=tar.gz,enum=zip,default=tar.gz"`
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
PrefixTemplate string `yaml:"prefix_template,omitempty" json:"prefix_template,omitempty"`
Files []File `yaml:"files,omitempty" json:"files,omitempty"`

View File

@ -139,10 +139,17 @@ archives:
#
# Default: copied from the source file
info:
# Templateable (since v1.14.0)
owner: root
# Templateable (since v1.14.0)
group: root
# Must be in time.RFC3339Nano format.
# Templateable (since v1.14.0)
mtime: '{{ .CommitDate }}'
# File mode.
mode: 0644
# Before and after hooks for each archive.

View File

@ -16,7 +16,8 @@ source:
name_template: '{{ .ProjectName }}'
# Format of the archive.
# Any format git-archive supports, this supports too.
#
# Valid formats are: tar, tgz, tar.gz, and zip.
#
# Default: 'tar.gz'
format: 'tar'