1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-16 03:52:12 +02:00
goreleaser/cmd/release.go

176 lines
6.6 KiB
Go
Raw Normal View History

package cmd
import (
"fmt"
"runtime"
"time"
"github.com/caarlos0/ctrlc"
"github.com/caarlos0/log"
"github.com/goreleaser/goreleaser/v2/internal/logext"
"github.com/goreleaser/goreleaser/v2/internal/middleware/errhandler"
"github.com/goreleaser/goreleaser/v2/internal/middleware/logging"
"github.com/goreleaser/goreleaser/v2/internal/middleware/skip"
"github.com/goreleaser/goreleaser/v2/internal/pipe/git"
"github.com/goreleaser/goreleaser/v2/internal/pipeline"
"github.com/goreleaser/goreleaser/v2/internal/skips"
"github.com/goreleaser/goreleaser/v2/pkg/context"
"github.com/spf13/cobra"
)
type releaseCmd struct {
cmd *cobra.Command
opts releaseOpts
}
type releaseOpts struct {
config string
releaseNotesFile string
releaseNotesTmpl string
releaseHeaderFile string
releaseHeaderTmpl string
releaseFooterFile string
releaseFooterTmpl string
autoSnapshot bool
snapshot bool
draft bool
failFast bool
clean bool
deprecated bool
parallelism int
timeout time.Duration
skips []string
}
func newReleaseCmd() *releaseCmd {
root := &releaseCmd{}
//nolint:dupl
cmd := &cobra.Command{
Use: "release",
Aliases: []string{"r"},
Short: "Releases the current project",
SilenceUsage: true,
SilenceErrors: true,
Args: cobra.NoArgs,
ValidArgsFunction: cobra.NoFileCompletions,
RunE: timedRunE("release", func(_ *cobra.Command, _ []string) error {
ctx, err := releaseProject(root.opts)
if err != nil {
return err
}
deprecateWarn(ctx)
return nil
}),
}
cmd.Flags().StringVarP(&root.opts.config, "config", "f", "", "Load configuration from file")
_ = cmd.MarkFlagFilename("config", "yaml", "yml")
cmd.Flags().StringVar(&root.opts.releaseNotesFile, "release-notes", "", "Load custom release notes from a markdown file (will skip GoReleaser changelog generation)")
_ = cmd.MarkFlagFilename("release-notes", "md", "mkd", "markdown")
cmd.Flags().StringVar(&root.opts.releaseHeaderFile, "release-header", "", "Load custom release notes header from a markdown file")
_ = cmd.MarkFlagFilename("release-header", "md", "mkd", "markdown")
cmd.Flags().StringVar(&root.opts.releaseFooterFile, "release-footer", "", "Load custom release notes footer from a markdown file")
_ = cmd.MarkFlagFilename("release-footer", "md", "mkd", "markdown")
cmd.Flags().StringVar(&root.opts.releaseNotesTmpl, "release-notes-tmpl", "", "Load custom release notes from a templated markdown file (overrides --release-notes)")
_ = cmd.MarkFlagFilename("release-notes-tmpl", "md", "mkd", "markdown")
cmd.Flags().StringVar(&root.opts.releaseHeaderTmpl, "release-header-tmpl", "", "Load custom release notes header from a templated markdown file (overrides --release-header)")
_ = cmd.MarkFlagFilename("release-header-tmpl", "md", "mkd", "markdown")
cmd.Flags().StringVar(&root.opts.releaseFooterTmpl, "release-footer-tmpl", "", "Load custom release notes footer from a templated markdown file (overrides --release-footer)")
_ = cmd.MarkFlagFilename("release-footer-tmpl", "md", "mkd", "markdown")
cmd.Flags().BoolVar(&root.opts.autoSnapshot, "auto-snapshot", false, "Automatically sets --snapshot if the repository is dirty")
cmd.Flags().BoolVar(&root.opts.snapshot, "snapshot", false, "Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts (implies --skip=announce,publish,validate)")
cmd.Flags().BoolVar(&root.opts.draft, "draft", false, "Whether to set the release to draft. Overrides release.draft in the configuration file")
cmd.Flags().BoolVar(&root.opts.failFast, "fail-fast", false, "Whether to abort the release publishing on the first error")
cmd.Flags().BoolVar(&root.opts.clean, "clean", false, "Removes the 'dist' directory")
cmd.Flags().IntVarP(&root.opts.parallelism, "parallelism", "p", 0, "Amount tasks to run concurrently (default: number of CPUs)")
_ = cmd.RegisterFlagCompletionFunc("parallelism", cobra.NoFileCompletions)
cmd.Flags().DurationVar(&root.opts.timeout, "timeout", 30*time.Minute, "Timeout to the entire release process")
_ = cmd.RegisterFlagCompletionFunc("timeout", cobra.NoFileCompletions)
cmd.Flags().BoolVar(&root.opts.deprecated, "deprecated", false, "Force print the deprecation message - tests only")
_ = cmd.Flags().MarkHidden("deprecated")
cmd.Flags().StringSliceVar(
&root.opts.skips,
"skip",
nil,
fmt.Sprintf("Skip the given options (valid options are %s)", skips.Release.String()),
)
_ = cmd.RegisterFlagCompletionFunc("skip", func(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return skips.Release.Complete(toComplete), cobra.ShellCompDirectiveDefault
})
root.cmd = cmd
return root
}
func releaseProject(options releaseOpts) (*context.Context, error) {
cfg, err := loadConfig(options.config)
if err != nil {
return nil, err
}
ctx, cancel := context.NewWithTimeout(cfg, options.timeout)
defer cancel()
if err := setupReleaseContext(ctx, options); err != nil {
return nil, err
}
return ctx, ctrlc.Default.Run(ctx, func() error {
for _, pipe := range pipeline.Pipeline {
feat: improve output and pipe skipping (#2480) * refactor: improve middleware Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: upload tests Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: twitter tests Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: source tests Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: snapshot tests Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * test: improved some tests Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: snapcraft skip Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip slack Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip sign Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip scoop Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip reddit Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip discord Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip publish Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip nfpm Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip milestone Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip custompublishers Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip checksums Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip changelog Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip brew Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip blob Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip before Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip artifactory Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip announce Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip defaults Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: cmds Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip docker Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * chore: todo Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: go.mod Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip release Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: remove old skip pipe errors Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip teams Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip brew Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix/test: skip smtp Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: lint issues Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip docker Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip brew and scoop Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip docker Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip http/artifactory Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * test: increase coverage Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * test: fix Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>
2021-09-18 15:21:29 +02:00
if err := skip.Maybe(
pipe,
logging.Log(
pipe.String(),
errhandler.Handle(pipe.Run),
),
)(ctx); err != nil {
return err
}
}
return nil
})
}
func setupReleaseContext(ctx *context.Context, options releaseOpts) error {
ctx.Action = context.ActionRelease
ctx.Deprecated = options.deprecated // test only
fix: set parallelism to match Linux container CPU (#3901) <!-- Hi, thanks for contributing! Please make sure you read our CONTRIBUTING guide. Also, add tests and the respective documentation changes as well. --> Currently Goreleaser uses `runtime.NumCPU()` as the default value if `--parallelism` is not set. However, this will get the number of CPUs on the host even when Goreleaser is run in a container with a limit on the maximum number of CPUs that can be used (typically in a Kubernetes pod). Actually, `docker run --cpus=1 goreleaser/goreleaser --debug` shows `parallelism: 4` on my machine. This behavior causes CPU throttling, which increases execution time and, in the worst case, terminates with an error. I ran into this problem with Jenkins where the agent runs on pod ([Kubernetes plugin for Jenkins](https://plugins.jenkins.io/kubernetes/)). This commit introduces [automaxprocs](https://github.com/uber-go/automaxprocs) to fix this issue. This library sets `GOMAXPROCS` to match Linux container CPU quota. I have also looked for a library that can get CPU quota more directly, but this seems to be the best I could find. The reason it is set in a different notation from the automaxprocs README is to prevent logs from being displayed ([comment](https://github.com/uber-go/automaxprocs/issues/18#issuecomment-511330567)). I would have liked to write a test, but this change is dependent on the number of CPUs in the execution environment, so I could not. Instead, I wrote a Dockerfile for testing ```Dockerfile FROM golang:1.20.2 WORKDIR /go/app RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin COPY . . RUN task build ``` and confirmed built binary shows expected parallelism by following commands: ```sh docker build --file Dockerfile.test . -t test-goreleaser docker run --cpus=1 test-goreleaser ./goreleaser build --snapshot --debug # parallelism: 1 docker run test-goreleaser ./goreleaser build --snapshot --debug # parallelism: 4 ``` I also ran the built binary on my Macbook and it was fine.
2023-04-02 22:16:41 +02:00
ctx.Parallelism = runtime.GOMAXPROCS(0)
if options.parallelism > 0 {
ctx.Parallelism = options.parallelism
}
log.Debugf("parallelism: %v", ctx.Parallelism)
ctx.ReleaseNotesFile = options.releaseNotesFile
ctx.ReleaseNotesTmpl = options.releaseNotesTmpl
ctx.ReleaseHeaderFile = options.releaseHeaderFile
ctx.ReleaseHeaderTmpl = options.releaseHeaderTmpl
ctx.ReleaseFooterFile = options.releaseFooterFile
ctx.ReleaseFooterTmpl = options.releaseFooterTmpl
ctx.Snapshot = options.snapshot
ctx.FailFast = options.failFast
ctx.Clean = options.clean
if options.autoSnapshot && git.CheckDirty(ctx) != nil {
log.Info("git repository is dirty and --auto-snapshot is set, implying --snapshot")
ctx.Snapshot = true
}
if options.draft {
ctx.Config.Release.Draft = true
}
if err := skips.SetRelease(ctx, options.skips...); err != nil {
return err
}
if ctx.Snapshot {
skips.Set(ctx, skips.Publish, skips.Announce, skips.Validate)
}
if skips.Any(ctx, skips.Publish) {
skips.Set(ctx, skips.Announce)
}
if skips.Any(ctx, skips.Release...) {
log.Warnf(
logext.Warning("skipping %s..."),
skips.String(ctx),
)
}
return nil
}