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

     1  package cmd
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os/exec"
     7  	"sync"
     8  
     9  	"github.com/caarlos0/ctrlc"
    10  	"github.com/caarlos0/log"
    11  	"github.com/charmbracelet/lipgloss"
    12  	"github.com/spf13/cobra"
    13  	"github.com/windmeup/goreleaser/internal/middleware/skip"
    14  	"github.com/windmeup/goreleaser/internal/pipe/defaults"
    15  	"github.com/windmeup/goreleaser/pkg/context"
    16  	"github.com/windmeup/goreleaser/pkg/healthcheck"
    17  )
    18  
    19  type healthcheckCmd struct {
    20  	cmd    *cobra.Command
    21  	config string
    22  	quiet  bool
    23  }
    24  
    25  func newHealthcheckCmd() *healthcheckCmd {
    26  	root := &healthcheckCmd{}
    27  	cmd := &cobra.Command{
    28  		Use:               "healthcheck",
    29  		Aliases:           []string{"hc"},
    30  		Short:             "Checks if needed tools are installed",
    31  		Long:              `Check if the needed tools are available in your $PATH, exits 1 if any of them are missing.`,
    32  		SilenceUsage:      true,
    33  		SilenceErrors:     true,
    34  		Args:              cobra.NoArgs,
    35  		ValidArgsFunction: cobra.NoFileCompletions,
    36  		RunE: func(cmd *cobra.Command, args []string) error {
    37  			if root.quiet {
    38  				log.Log = log.New(io.Discard)
    39  			}
    40  
    41  			cfg, err := loadConfig(root.config)
    42  			if err != nil {
    43  				return err
    44  			}
    45  			ctx := context.New(cfg)
    46  
    47  			if err := ctrlc.Default.Run(ctx, func() error {
    48  				log.Info(boldStyle.Render("checking tools..."))
    49  
    50  				err := defaults.Pipe{}.Run(ctx)
    51  				if err != nil {
    52  					return err
    53  				}
    54  
    55  				log.IncreasePadding()
    56  				defer log.ResetPadding()
    57  
    58  				var errs []error
    59  				for _, hc := range healthcheck.Healthcheckers {
    60  					_ = skip.Maybe(hc, func(ctx *context.Context) error {
    61  						for _, tool := range hc.Dependencies(ctx) {
    62  							if err := checkPath(tool); err != nil {
    63  								errs = append(errs, err)
    64  							}
    65  						}
    66  						return nil
    67  					})(ctx)
    68  				}
    69  
    70  				if len(errs) == 0 {
    71  					return nil
    72  				}
    73  
    74  				return fmt.Errorf("one or more needed tools are not present")
    75  			}); err != nil {
    76  				return err
    77  			}
    78  
    79  			log.Infof(boldStyle.Render("done!"))
    80  			return nil
    81  		},
    82  	}
    83  
    84  	cmd.Flags().StringVarP(&root.config, "config", "f", "", "Configuration file")
    85  	_ = cmd.MarkFlagFilename("config", "yaml", "yml")
    86  	cmd.Flags().BoolVarP(&root.quiet, "quiet", "q", false, "Quiet mode: no output")
    87  	_ = cmd.Flags().MarkHidden("deprecated")
    88  
    89  	root.cmd = cmd
    90  	return root
    91  }
    92  
    93  var toolsChecked = &sync.Map{}
    94  
    95  func checkPath(tool string) error {
    96  	if _, ok := toolsChecked.LoadOrStore(tool, true); ok {
    97  		return nil
    98  	}
    99  	if _, err := exec.LookPath(tool); err != nil {
   100  		st := log.Styles[log.ErrorLevel]
   101  		log.Warnf("%s %s - %s", st.Render("⚠"), codeStyle.Render(tool), st.Render("not present in path"))
   102  		return err
   103  	}
   104  	st := lipgloss.NewStyle().Foreground(lipgloss.Color("2")).Bold(true)
   105  	log.Infof("%s %s", st.Render("✓"), codeStyle.Render(tool))
   106  	return nil
   107  }