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: add extra files to source archives #3102

Merged
merged 9 commits into from Aug 25, 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
49 changes: 49 additions & 0 deletions internal/pipe/sourcearchive/source.go
Expand Up @@ -5,9 +5,11 @@ import (
"path/filepath"

"github.com/caarlos0/log"
"github.com/goreleaser/goreleaser/internal/archivefiles"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/git"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
)

Expand All @@ -34,17 +36,29 @@ func (Pipe) Run(ctx *context.Context) (err error) {
args := []string{
"archive",
"-o", path,
"--format", ctx.Config.Source.Format,
}

if ctx.Config.Source.PrefixTemplate != "" {
prefix, err := tmpl.New(ctx).Apply(ctx.Config.Source.PrefixTemplate)
if err != nil {
return err
}
args = append(args, "--prefix", prefix)
}

files, err := evalFiles(ctx)
if err != nil {
return err
}
for _, f := range files {
args = append(args, "--add-file", f)
}

args = append(args, ctx.Git.FullCommit)
out, err := git.Clean(git.Run(ctx, args...))
log.Debug(out)

ctx.Artifacts.Add(&artifact.Artifact{
Type: artifact.UploadableSourceArchive,
Name: filename,
Expand All @@ -56,6 +70,41 @@ func (Pipe) Run(ctx *context.Context) (err error) {
return err
}

// to reuse the archivefiles packages, we do something funky:
// - convert the []string to []config.File
// - eval it in archivefiles
// - convert it back to []string
//
// we also handle files already tracked, as if we add them again,
// they'll get duplicated in the archive.
func evalFiles(ctx *context.Context) ([]string, error) {
var files []config.File
for _, f := range ctx.Config.Source.Files {
files = append(files, config.File{
Source: f,
})
}
addFiles, err := archivefiles.Eval(tmpl.New(ctx), files)
if err != nil {
return nil, err
}

var result []string
for _, f := range addFiles {
if isTracked(ctx, f.Source) {
continue
}
result = append(result, f.Source)
}
return result, nil
}

// check if file is tracked, and, if it is we should not add it to the archive again.
func isTracked(ctx *context.Context, path string) bool {
_, err := git.Run(ctx, "ls-files", "--error-unmatch", path)
return err == nil
}

// Default sets the pipe defaults.
func (Pipe) Default(ctx *context.Context) error {
archive := &ctx.Config.Source
Expand Down
45 changes: 44 additions & 1 deletion internal/pipe/sourcearchive/source_test.go
@@ -1,6 +1,7 @@
package sourcearchive

import (
"archive/zip"
"os"
"path/filepath"
"testing"
Expand All @@ -20,9 +21,12 @@ func TestArchive(t *testing.T) {

testlib.GitInit(t)
require.NoError(t, os.WriteFile("code.txt", []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))

ctx := context.New(config.Project{
ProjectName: "foo",
Expand All @@ -31,6 +35,9 @@ func TestArchive(t *testing.T) {
Format: format,
Enabled: true,
PrefixTemplate: "{{ .ProjectName }}-{{ .Version }}/",
Files: []string{
"*.txt",
},
},
})
ctx.Git.FullCommit = "HEAD"
Expand All @@ -49,13 +56,49 @@ func TestArchive(t *testing.T) {
artifact.ExtraFormat: format,
},
}, *artifacts[0])
stat, err := os.Stat(filepath.Join(tmp, "dist", "foo-1.0.0."+format))
path := filepath.Join(tmp, "dist", "foo-1.0.0."+format)
stat, err := os.Stat(path)
require.NoError(t, err)
require.Greater(t, stat.Size(), int64(100))

if format != "zip" {
return
}

f, err := os.Open(path)
require.NoError(t, err)
z, err := zip.NewReader(f, stat.Size())
require.NoError(t, err)

var paths []string
for _, zf := range z.File {
paths = append(paths, zf.Name)
}
require.Equal(t, []string{
"foo-1.0.0/",
"foo-1.0.0/README.md",
"foo-1.0.0/code.py",
"foo-1.0.0/code.txt",
"foo-1.0.0/added-later.txt",
}, paths)
})
}
}

func TestInvalidFormat(t *testing.T) {
ctx := context.New(config.Project{
Dist: t.TempDir(),
ProjectName: "foo",
Source: config.Source{
Format: "7z",
Enabled: true,
PrefixTemplate: "{{ .ProjectName }}-{{ .Version }}/",
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.EqualError(t, Pipe{}.Run(ctx), "fatal: Unknown archive format '7z'")
}

func TestDefault(t *testing.T) {
ctx := context.New(config.Project{})
require.NoError(t, Pipe{}.Default(ctx))
Expand Down
9 changes: 5 additions & 4 deletions pkg/config/config.go
Expand Up @@ -876,10 +876,11 @@ 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"`
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
PrefixTemplate string `yaml:"prefix_template,omitempty" json:"prefix_template,omitempty"`
NameTemplate string `yaml:"name_template,omitempty" json:"name_template,omitempty"`
Format string `yaml:"format,omitempty" json:"format,omitempty"`
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
PrefixTemplate string `yaml:"prefix_template,omitempty" json:"prefix_template,omitempty"`
Files []string `yaml:"files,omitempty" json:"files,omitempty"`
}

// Project includes all project configuration.
Expand Down
11 changes: 11 additions & 0 deletions www/docs/customization/source.md
Expand Up @@ -23,6 +23,17 @@ source:
# String to prepend to each filename in the archive.
# Defaults to empty
prefix_template: '{{ .ProjectName }}-{{ .Version }}/'

# Additional files/template/globs you want to add to the source archive.
# Will use --add-file of git-archive.
# Defaults to empty.
files:
- LICENSE.txt
- README_{{.Os}}.md
- CHANGELOG.md
- docs/*
- design/*.png
- templates/**/*
```

!!! tip
Expand Down