github.com/windmeup/goreleaser@v1.21.95/cmd/root.go (about)

     1  package cmd
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	goversion "github.com/caarlos0/go-version"
     9  	"github.com/caarlos0/log"
    10  	"github.com/charmbracelet/lipgloss"
    11  	"github.com/spf13/cobra"
    12  	"github.com/windmeup/goreleaser/pkg/context"
    13  	cobracompletefig "github.com/withfig/autocomplete-tools/integrations/cobra"
    14  )
    15  
    16  var (
    17  	boldStyle = lipgloss.NewStyle().Bold(true)
    18  	codeStyle = lipgloss.NewStyle().Italic(true)
    19  )
    20  
    21  func Execute(version goversion.Info, exit func(int), args []string) {
    22  	newRootCmd(version, exit).Execute(args)
    23  }
    24  
    25  func (cmd *rootCmd) Execute(args []string) {
    26  	cmd.cmd.SetArgs(args)
    27  
    28  	if shouldPrependRelease(cmd.cmd, args) {
    29  		cmd.cmd.SetArgs(append([]string{"release"}, args...))
    30  	}
    31  
    32  	if err := cmd.cmd.Execute(); err != nil {
    33  		code := 1
    34  		msg := "command failed"
    35  		eerr := &exitError{}
    36  		if errors.As(err, &eerr) {
    37  			code = eerr.code
    38  			if eerr.details != "" {
    39  				msg = eerr.details
    40  			}
    41  		}
    42  		log.WithError(err).Error(msg)
    43  		cmd.exit(code)
    44  	}
    45  }
    46  
    47  type rootCmd struct {
    48  	cmd     *cobra.Command
    49  	verbose bool
    50  	exit    func(int)
    51  
    52  	// Deprecated: use verbose instead.
    53  	debug bool
    54  }
    55  
    56  func newRootCmd(version goversion.Info, exit func(int)) *rootCmd {
    57  	root := &rootCmd{
    58  		exit: exit,
    59  	}
    60  	cmd := &cobra.Command{
    61  		Use:   "goreleaser",
    62  		Short: "Deliver Go binaries as fast and easily as possible",
    63  		Long: `GoReleaser is a release automation tool for Go projects.
    64  Its goal is to simplify the build, release and publish steps while providing variant customization options for all steps.
    65  
    66  GoReleaser is built for CI tools, you only need to download and execute it in your build script. Of course, you can also install it locally if you wish.
    67  
    68  You can customize your entire release process through a single .goreleaser.yaml file.
    69  
    70  Check out our website for more information, examples and documentation: https://goreleaser.com
    71  `,
    72  		Version:           version.String(),
    73  		SilenceUsage:      true,
    74  		SilenceErrors:     true,
    75  		Args:              cobra.NoArgs,
    76  		ValidArgsFunction: cobra.NoFileCompletions,
    77  		PersistentPreRun: func(_ *cobra.Command, _ []string) {
    78  			if root.verbose || root.debug {
    79  				log.SetLevel(log.DebugLevel)
    80  				log.Debug("verbose output enabled")
    81  			}
    82  		},
    83  		PersistentPostRun: func(_ *cobra.Command, _ []string) {
    84  			log.Info("thanks for using goreleaser!")
    85  		},
    86  	}
    87  	cmd.SetVersionTemplate("{{.Version}}")
    88  
    89  	cmd.PersistentFlags().BoolVar(&root.debug, "debug", false, "Enable verbose mode")
    90  	cmd.PersistentFlags().BoolVar(&root.verbose, "verbose", false, "Enable verbose mode")
    91  	_ = cmd.Flags().MarkDeprecated("debug", "please use --verbose instead")
    92  	_ = cmd.Flags().MarkHidden("debug")
    93  	cmd.AddCommand(
    94  		newBuildCmd().cmd,
    95  		newReleaseCmd().cmd,
    96  		newCheckCmd().cmd,
    97  		newHealthcheckCmd().cmd,
    98  		newInitCmd().cmd,
    99  		newDocsCmd().cmd,
   100  		newManCmd().cmd,
   101  		newSchemaCmd().cmd,
   102  		cobracompletefig.CreateCompletionSpecCommand(),
   103  	)
   104  	root.cmd = cmd
   105  	return root
   106  }
   107  
   108  func shouldPrependRelease(cmd *cobra.Command, args []string) bool {
   109  	// find current cmd, if its not root, it means the user actively
   110  	// set a command, so let it go
   111  	xmd, _, _ := cmd.Find(args)
   112  	if xmd != cmd {
   113  		return false
   114  	}
   115  
   116  	// allow help and the two __complete commands.
   117  	if len(args) > 0 && (args[0] == "help" || args[0] == "completion" ||
   118  		args[0] == cobra.ShellCompRequestCmd || args[0] == cobra.ShellCompNoDescRequestCmd) {
   119  		return false
   120  	}
   121  
   122  	// if we have != 1 args, assume its a release
   123  	if len(args) != 1 {
   124  		return true
   125  	}
   126  
   127  	// given that its 1, check if its one of the valid standalone flags
   128  	// for the root cmd
   129  	for _, s := range []string{"-h", "--help", "-v", "--version"} {
   130  		if s == args[0] {
   131  			// if it is, we should run the root cmd
   132  			return false
   133  		}
   134  	}
   135  
   136  	// otherwise, we should probably prepend release
   137  	return true
   138  }
   139  
   140  func deprecateWarn(ctx *context.Context) {
   141  	if ctx.Deprecated {
   142  		log.Warn(boldStyle.Render("you are using deprecated options, check the output above for details"))
   143  	}
   144  }
   145  
   146  func timedRunE(verb string, rune func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error {
   147  	return func(cmd *cobra.Command, args []string) error {
   148  		start := time.Now()
   149  
   150  		log.Infof(boldStyle.Render(fmt.Sprintf("starting %s...", verb)))
   151  
   152  		if err := rune(cmd, args); err != nil {
   153  			return wrapError(err, boldStyle.Render(fmt.Sprintf("%s failed after %s", verb, time.Since(start).Truncate(time.Second))))
   154  		}
   155  
   156  		log.Infof(boldStyle.Render(fmt.Sprintf("%s succeeded after %s", verb, time.Since(start).Truncate(time.Second))))
   157  		return nil
   158  	}
   159  }