diff --git a/.goreleaser.yaml b/.goreleaser.yaml index d525dd5ea..a5222ce00 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -13,6 +13,8 @@ snapshot: gomod: proxy: true +report_sizes: true + builds: - env: - CGO_ENABLED=0 diff --git a/internal/artifact/artifact.go b/internal/artifact/artifact.go index 25d5eee3c..a51649eaf 100644 --- a/internal/artifact/artifact.go +++ b/internal/artifact/artifact.go @@ -138,6 +138,7 @@ const ( ExtraRefresh = "Refresh" ExtraReplaces = "Replaces" ExtraDigest = "Digest" + ExtraSize = "Size" ) // Extras represents the extra fields in an artifact. diff --git a/internal/pipe/reportsizes/reportsizes.go b/internal/pipe/reportsizes/reportsizes.go new file mode 100644 index 000000000..b15c13a2a --- /dev/null +++ b/internal/pipe/reportsizes/reportsizes.go @@ -0,0 +1,48 @@ +package reportsizes + +import ( + "os" + "path/filepath" + + "github.com/caarlos0/log" + "github.com/docker/go-units" + "github.com/goreleaser/goreleaser/internal/artifact" + "github.com/goreleaser/goreleaser/pkg/context" +) + +type Pipe struct{} + +func (Pipe) Skip(ctx *context.Context) bool { return !ctx.Config.ReportSizes } +func (Pipe) String() string { return "size reports" } + +func (Pipe) Run(ctx *context.Context) error { + cwd, err := os.Getwd() + if err != nil { + return err + } + return ctx.Artifacts.Filter(artifact.Or( + artifact.ByType(artifact.Binary), + artifact.ByType(artifact.UniversalBinary), + artifact.ByType(artifact.UploadableArchive), + artifact.ByType(artifact.PublishableSnapcraft), + artifact.ByType(artifact.LinuxPackage), + artifact.ByType(artifact.CArchive), + artifact.ByType(artifact.CShared), + artifact.ByType(artifact.Header), + )).Visit(func(a *artifact.Artifact) error { + stat, err := os.Stat(a.Path) + if err != nil { + return err + } + relpath := a.Path + if filepath.IsAbs(a.Path) { + relpath, err = filepath.Rel(cwd, a.Path) + if err != nil { + return err + } + } + a.Extra[artifact.ExtraSize] = stat.Size() + log.WithField("path", relpath).Info(units.BytesSize(float64(stat.Size()))) + return nil + }) +} diff --git a/internal/pipe/reportsizes/reportsizes_test.go b/internal/pipe/reportsizes/reportsizes_test.go new file mode 100644 index 000000000..423e8244e --- /dev/null +++ b/internal/pipe/reportsizes/reportsizes_test.go @@ -0,0 +1,67 @@ +package reportsizes + +import ( + "os" + "path/filepath" + "testing" + + "github.com/goreleaser/goreleaser/internal/artifact" + "github.com/goreleaser/goreleaser/internal/testctx" + "github.com/goreleaser/goreleaser/pkg/config" + "github.com/stretchr/testify/require" +) + +func TestString(t *testing.T) { + require.NotEmpty(t, Pipe{}.String()) +} + +func TestSkip(t *testing.T) { + t.Run("skip", func(t *testing.T) { + require.True(t, Pipe{}.Skip(testctx.NewWithCfg(config.Project{ + ReportSizes: false, + }))) + }) + t.Run("dont skip", func(t *testing.T) { + require.False(t, Pipe{}.Skip(testctx.NewWithCfg(config.Project{ + ReportSizes: true, + }))) + }) +} + +func TestRun(t *testing.T) { + ctx := testctx.New() + for i, tp := range []artifact.Type{ + artifact.Binary, + artifact.UniversalBinary, + artifact.UploadableArchive, + artifact.PublishableSnapcraft, + artifact.LinuxPackage, + artifact.CArchive, + artifact.CShared, + artifact.Header, + } { + if i%2 == 0 { + cw, err := os.Getwd() + require.NoError(t, err) + ctx.Artifacts.Add(&artifact.Artifact{ + Name: "foo", + Path: filepath.Join(cw, "reportsizes.go"), + Extra: map[string]any{}, + Type: tp, + }) + continue + } + ctx.Artifacts.Add(&artifact.Artifact{ + Name: "foo", + Path: "reportsizes.go", + Extra: map[string]any{}, + Type: tp, + }) + } + + require.NoError(t, Pipe{}.Run(ctx)) + + for _, art := range ctx.Artifacts.List() { + require.NotZero(t, artifact.ExtraOr[int64](*art, artifact.ExtraSize, 0)) + } +} diff --git a/internal/pipeline/pipeline.go b/internal/pipeline/pipeline.go index 78a247b22..01a9ff454 100644 --- a/internal/pipeline/pipeline.go +++ b/internal/pipeline/pipeline.go @@ -25,6 +25,7 @@ import ( "github.com/goreleaser/goreleaser/internal/pipe/nfpm" "github.com/goreleaser/goreleaser/internal/pipe/prebuild" "github.com/goreleaser/goreleaser/internal/pipe/publish" + "github.com/goreleaser/goreleaser/internal/pipe/reportsizes" "github.com/goreleaser/goreleaser/internal/pipe/sbom" "github.com/goreleaser/goreleaser/internal/pipe/scoop" "github.com/goreleaser/goreleaser/internal/pipe/semver" @@ -77,7 +78,7 @@ var BuildPipeline = []Piper{ // BuildCmdPipeline is the pipeline run by goreleaser build. // nolint:gochecknoglobals -var BuildCmdPipeline = append(BuildPipeline, metadata.Pipe{}) +var BuildCmdPipeline = append(BuildPipeline, metadata.Pipe{}, reportsizes.Pipe{}) // Pipeline contains all pipe implementations in order. // nolint: gochecknoglobals @@ -109,6 +110,8 @@ var Pipeline = append( scoop.Pipe{}, // create chocolatey pkg and publish chocolatey.Pipe{}, + // reports artifacts sizes to the log and to artifacts.json + reportsizes.Pipe{}, // create and push docker images docker.Pipe{}, // publishes artifacts diff --git a/pkg/config/config.go b/pkg/config/config.go index ae177870f..d3e62c014 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -975,6 +975,7 @@ type Project struct { SBOMs []SBOM `yaml:"sboms,omitempty" json:"sboms,omitempty"` Chocolateys []Chocolatey `yaml:"chocolateys,omitempty" json:"chocolateys,omitempty"` Git Git `yaml:"git,omitempty" json:"git,omitempty"` + ReportSizes bool `yaml:"report_sizes,omitempty" json:"report_sizes,omitempty"` UniversalBinaries []UniversalBinary `yaml:"universal_binaries,omitempty" json:"universal_binaries,omitempty"` diff --git a/www/docs/customization/reportsizes.md b/www/docs/customization/reportsizes.md new file mode 100644 index 000000000..9f63c4a8f --- /dev/null +++ b/www/docs/customization/reportsizes.md @@ -0,0 +1,26 @@ +# Report Sizes + +> Since v1.18 + +You might want to enable this if you want to keep an eye on your binary/package +sizes. + +It'll report the size of each artifact of the following types to the build +output, as well as on `dist/artifacts.json`: + +- `Binary,` +- `UniversalBinary,` +- `UploadableArchive,` +- `PublishableSnapcraft,` +- `LinuxPackage,` +- `CArchive,` +- `CShared,` +- `Header,` + +Here's the available configuration options: + +```yaml +# .goreleaser.yaml +# Whether to enable the size reporting or not. +report_sizes: true +``` diff --git a/www/mkdocs.yml b/www/mkdocs.yml index 7a0310cb7..3c94a04ed 100644 --- a/www/mkdocs.yml +++ b/www/mkdocs.yml @@ -116,6 +116,7 @@ nav: - customization/docker_manifest.md - customization/ko.md - customization/sbom.md + - customization/reportsizes.md - Signing: - Checksums and artifacts: customization/sign.md - Docker Images and Manifests: customization/docker_sign.md