Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow to template archives.files.info #3630

Merged
merged 1 commit into from Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions internal/archivefiles/archivefiles.go
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"path/filepath"
"sort"
"time"

"github.com/caarlos0/log"
"github.com/goreleaser/fileglob"
Expand All @@ -26,6 +27,25 @@ func Eval(template *tmpl.Template, files []config.File) ([]config.File, error) {
return result, fmt.Errorf("globbing failed for pattern %s: %w", replaced, err)
}

f.Info.Owner, err = template.Apply(f.Info.Owner)
if err != nil {
return result, fmt.Errorf("failed to apply template %s: %w", f.Info.Owner, err)
}
f.Info.Group, err = template.Apply(f.Info.Group)
if err != nil {
return result, fmt.Errorf("failed to apply template %s: %w", f.Info.Group, err)
}
f.Info.MTime, err = template.Apply(f.Info.MTime)
if err != nil {
return result, fmt.Errorf("failed to apply template %s: %w", f.Info.MTime, err)
}
if f.Info.MTime != "" {
f.Info.ParsedMTime, err = time.Parse(time.RFC3339Nano, f.Info.MTime)
if err != nil {
return result, fmt.Errorf("failed to parse %s: %w", f.Info.MTime, err)
}
}

for _, file := range files {
result = append(result, config.File{
Source: file,
Expand Down
134 changes: 105 additions & 29 deletions internal/archivefiles/archivefiles_test.go
Expand Up @@ -4,6 +4,7 @@ import (
"testing"
"time"

"github.com/goreleaser/goreleaser/internal/testlib"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
Expand All @@ -12,7 +13,82 @@ import (

func TestEval(t *testing.T) {
now := time.Now().Truncate(time.Second)
tmpl := tmpl.New(context.New(config.Project{}))
ctx := context.New(config.Project{
Env: []string{"OWNER=carlos"},
})
ctx.Git.CommitDate = now
tmpl := tmpl.New(ctx)

t.Run("templated info", func(t *testing.T) {
result, err := Eval(tmpl, []config.File{
{
Source: "./testdata/**/d.txt",
Destination: "var/foobar/d.txt",
Info: config.FileInfo{
MTime: "{{.CommitDate}}",
Owner: "{{ .Env.OWNER }}",
Group: "{{ .Env.OWNER }}",
},
},
})

require.NoError(t, err)
require.Equal(t, []config.File{
{
Source: "testdata/a/b/c/d.txt",
Destination: "var/foobar/d.txt/testdata/a/b/c/d.txt",
Info: config.FileInfo{
MTime: now.UTC().Format(time.RFC3339),
ParsedMTime: now.UTC(),
Owner: "carlos",
Group: "carlos",
},
},
}, result)
})

t.Run("template info errors", func(t *testing.T) {
t.Run("owner", func(t *testing.T) {
_, err := Eval(tmpl, []config.File{{
Source: "./testdata/**/d.txt",
Destination: "var/foobar/d.txt",
Info: config.FileInfo{
Owner: "{{ .Env.NOPE }}",
},
}})
testlib.RequireTemplateError(t, err)
})
t.Run("group", func(t *testing.T) {
_, err := Eval(tmpl, []config.File{{
Source: "./testdata/**/d.txt",
Destination: "var/foobar/d.txt",
Info: config.FileInfo{
Group: "{{ .Env.NOPE }}",
},
}})
testlib.RequireTemplateError(t, err)
})
t.Run("mtime", func(t *testing.T) {
_, err := Eval(tmpl, []config.File{{
Source: "./testdata/**/d.txt",
Destination: "var/foobar/d.txt",
Info: config.FileInfo{
MTime: "{{ .Env.NOPE }}",
},
}})
testlib.RequireTemplateError(t, err)
})
t.Run("mtime format", func(t *testing.T) {
_, err := Eval(tmpl, []config.File{{
Source: "./testdata/**/d.txt",
Destination: "var/foobar/d.txt",
Info: config.FileInfo{
MTime: "2005-123-123",
},
}})
require.Error(t, err)
})
})

t.Run("single file", func(t *testing.T) {
result, err := Eval(tmpl, []config.File{
Expand Down Expand Up @@ -68,10 +144,10 @@ func TestEval(t *testing.T) {
Source: "./testdata/a",
Destination: "usr/local/test",
Info: config.FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o755,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o755,
ParsedMTime: now,
},
},
})
Expand All @@ -82,30 +158,30 @@ func TestEval(t *testing.T) {
Source: "testdata/a/a.txt",
Destination: "usr/local/test/testdata/a/a.txt",
Info: config.FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o755,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o755,
ParsedMTime: now,
},
},
{
Source: "testdata/a/b/a.txt",
Destination: "usr/local/test/testdata/a/b/a.txt",
Info: config.FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o755,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o755,
ParsedMTime: now,
},
},
{
Source: "testdata/a/b/c/d.txt",
Destination: "usr/local/test/testdata/a/b/c/d.txt",
Info: config.FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o755,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o755,
ParsedMTime: now,
},
},
}, result)
Expand All @@ -118,10 +194,10 @@ func TestEval(t *testing.T) {
Destination: "usr/local/test",
StripParent: true,
Info: config.FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o755,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o755,
ParsedMTime: now,
},
},
})
Expand All @@ -132,20 +208,20 @@ func TestEval(t *testing.T) {
Source: "testdata/a/a.txt",
Destination: "usr/local/test/a.txt",
Info: config.FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o755,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o755,
ParsedMTime: now,
},
},
{
Source: "testdata/a/b/c/d.txt",
Destination: "usr/local/test/d.txt",
Info: config.FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o755,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o755,
ParsedMTime: now,
},
},
}, result)
Expand Down
4 changes: 2 additions & 2 deletions pkg/archive/gzip/gzip.go
Expand Up @@ -48,10 +48,10 @@ func (a Archive) Add(f config.File) error {
return nil
}
a.gw.Header.Name = f.Destination
if f.Info.MTime.IsZero() {
if f.Info.ParsedMTime.IsZero() {
a.gw.Header.ModTime = info.ModTime()
} else {
a.gw.Header.ModTime = f.Info.MTime
a.gw.Header.ModTime = f.Info.ParsedMTime
}
_, err = io.Copy(a.gw, file)
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/archive/gzip/gzip_test.go
Expand Up @@ -63,7 +63,7 @@ func TestGzFileCustomMtime(t *testing.T) {
Destination: "sub1/sub2/subfoo.txt",
Source: "../testdata/sub1/sub2/subfoo.txt",
Info: config.FileInfo{
MTime: now,
ParsedMTime: now,
},
}))
require.NoError(t, archive.Close())
Expand Down
4 changes: 2 additions & 2 deletions pkg/archive/tar/tar.go
Expand Up @@ -45,8 +45,8 @@ func (a Archive) Add(f config.File) error {
return fmt.Errorf("%s: %w", f.Source, err)
}
header.Name = f.Destination
if !f.Info.MTime.IsZero() {
header.ModTime = f.Info.MTime
if !f.Info.ParsedMTime.IsZero() {
header.ModTime = f.Info.ParsedMTime
}
if f.Info.Mode != 0 {
header.Mode = int64(f.Info.Mode)
Expand Down
8 changes: 4 additions & 4 deletions pkg/archive/tar/tar_test.go
Expand Up @@ -114,10 +114,10 @@ func TestTarFileInfo(t *testing.T) {
Source: "../testdata/foo.txt",
Destination: "nope.txt",
Info: config.FileInfo{
Mode: 0o755,
Owner: "carlos",
Group: "root",
MTime: now,
Mode: 0o755,
Owner: "carlos",
Group: "root",
ParsedMTime: now,
},
}))

Expand Down
8 changes: 4 additions & 4 deletions pkg/archive/targz/targz_test.go
Expand Up @@ -119,10 +119,10 @@ func TestTarGzFileInfo(t *testing.T) {
Source: "../testdata/foo.txt",
Destination: "nope.txt",
Info: config.FileInfo{
Mode: 0o755,
Owner: "carlos",
Group: "root",
MTime: now,
Mode: 0o755,
Owner: "carlos",
Group: "root",
ParsedMTime: now,
},
}))

Expand Down
8 changes: 4 additions & 4 deletions pkg/archive/tarxz/tarxz_test.go
Expand Up @@ -118,10 +118,10 @@ func TestTarXzFileInfo(t *testing.T) {
Source: "../testdata/foo.txt",
Destination: "nope.txt",
Info: config.FileInfo{
Mode: 0o755,
Owner: "carlos",
Group: "root",
MTime: now,
Mode: 0o755,
Owner: "carlos",
Group: "root",
ParsedMTime: now,
},
}))

Expand Down
4 changes: 2 additions & 2 deletions pkg/archive/zip/zip.go
Expand Up @@ -49,8 +49,8 @@ func (a Archive) Add(f config.File) error {
}
header.Name = f.Destination
header.Method = zip.Deflate
if !f.Info.MTime.IsZero() {
header.Modified = f.Info.MTime
if !f.Info.ParsedMTime.IsZero() {
header.Modified = f.Info.ParsedMTime
}
if f.Info.Mode != 0 {
header.SetMode(f.Info.Mode)
Expand Down
8 changes: 4 additions & 4 deletions pkg/archive/zip/zip_test.go
Expand Up @@ -117,10 +117,10 @@ func TestZipFileInfo(t *testing.T) {
Source: "../testdata/foo.txt",
Destination: "nope.txt",
Info: config.FileInfo{
Mode: 0o755,
Owner: "carlos",
Group: "root",
MTime: now,
Mode: 0o755,
Owner: "carlos",
Group: "root",
ParsedMTime: now,
},
}))

Expand Down
9 changes: 5 additions & 4 deletions pkg/config/config.go
Expand Up @@ -428,10 +428,11 @@ type File struct {

// FileInfo is the file info of a file.
type FileInfo struct {
Owner string `yaml:"owner,omitempty" json:"owner,omitempty"`
Group string `yaml:"group,omitempty" json:"group,omitempty"`
Mode os.FileMode `yaml:"mode,omitempty" json:"mode,omitempty"`
MTime time.Time `yaml:"mtime,omitempty" json:"mtime,omitempty"`
Owner string `yaml:"owner,omitempty" json:"owner,omitempty"`
Group string `yaml:"group,omitempty" json:"group,omitempty"`
Mode os.FileMode `yaml:"mode,omitempty" json:"mode,omitempty"`
MTime string `yaml:"mtime,omitempty" json:"mtime,omitempty"`
ParsedMTime time.Time `yaml:"-" json:"-"`
}

// UnmarshalYAML is a custom unmarshaler that wraps strings in arrays.
Expand Down
9 changes: 5 additions & 4 deletions pkg/config/config_archive_files_test.go
Expand Up @@ -84,10 +84,11 @@ files:
Source: "./foobar",
Destination: "./barzaz",
Info: FileInfo{
Owner: "carlos",
Group: "users",
Mode: 0o644,
MTime: now,
Owner: "carlos",
Group: "users",
Mode: 0o644,
MTime: now.Format(time.RFC3339Nano),
ParsedMTime: time.Time{},
},
},
}, actual.Files)
Expand Down
11 changes: 9 additions & 2 deletions www/docs/customization/archive.md
Expand Up @@ -83,11 +83,18 @@ archives:
# Not all fields are supported by all formats available formats.
# Defaults to the file info of the actual file if not provided.
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
# format is `time.RFC3339Nano`
mtime: 2008-01-02T15:04:05Z

# Before and after hooks for each archive.
# Skipped if archive format is binary.
Expand Down