1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-24 04:16:27 +02:00
goreleaser/cmd/healthcheck.go
Carlos Alexandro Becker 874d698564
feat: add healthcheck cmd (#3826)
here's an idea: `goreleaser healthcheck`

It'll check if the needed dependencies (docker, git, etc) are available
in the path... this way users can preemptively run it before releasing
or to debug issues.

What do you think?

Here's how it looks like:

<img width="1007" alt="CleanShot 2023-03-02 at 23 24 26@2x"
src="https://user-images.githubusercontent.com/245435/222615682-d9cd0733-d900-43d1-9166-23b2be589b3a.png">

---------

Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
2023-03-03 09:50:15 -03:00

108 lines
2.6 KiB
Go

package cmd
import (
"fmt"
"io"
"os/exec"
"sync"
"github.com/caarlos0/ctrlc"
"github.com/caarlos0/log"
"github.com/charmbracelet/lipgloss"
"github.com/goreleaser/goreleaser/internal/middleware/skip"
"github.com/goreleaser/goreleaser/internal/pipe/defaults"
"github.com/goreleaser/goreleaser/pkg/context"
"github.com/goreleaser/goreleaser/pkg/healthcheck"
"github.com/spf13/cobra"
)
type healthcheckCmd struct {
cmd *cobra.Command
config string
quiet bool
deprecated bool
}
func newHealthcheckCmd() *healthcheckCmd {
root := &healthcheckCmd{}
cmd := &cobra.Command{
Use: "healthcheck",
Aliases: []string{"hc"},
Short: "Checks if needed tools are installed",
SilenceUsage: true,
SilenceErrors: true,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
if root.quiet {
log.Log = log.New(io.Discard)
}
cfg, err := loadConfig(root.config)
if err != nil {
return err
}
ctx := context.New(cfg)
ctx.Deprecated = root.deprecated
if err := ctrlc.Default.Run(ctx, func() error {
log.Info(boldStyle.Render("checking tools..."))
err := defaults.Pipe{}.Run(ctx)
if err != nil {
return err
}
log.IncreasePadding()
defer log.ResetPadding()
var errs []error
for _, hc := range healthcheck.Healthcheckers {
_ = skip.Maybe(hc, func(ctx *context.Context) error {
for _, tool := range hc.Dependencies(ctx) {
if err := checkPath(tool); err != nil {
errs = append(errs, err)
}
}
return nil
})(ctx)
}
if len(errs) == 0 {
return nil
}
return fmt.Errorf("one or more needed tools are not present")
}); err != nil {
return err
}
log.Infof(boldStyle.Render("done!"))
return nil
},
}
cmd.Flags().StringVarP(&root.config, "config", "f", "", "Configuration file")
cmd.Flags().BoolVarP(&root.quiet, "quiet", "q", false, "Quiet mode: no output")
cmd.Flags().BoolVar(&root.deprecated, "deprecated", false, "Force print the deprecation message - tests only")
_ = cmd.Flags().MarkHidden("deprecated")
root.cmd = cmd
return root
}
var toolsChecked = &sync.Map{}
func checkPath(tool string) error {
if _, ok := toolsChecked.LoadOrStore(tool, true); ok {
return nil
}
if _, err := exec.LookPath(tool); err != nil {
st := log.Styles[log.ErrorLevel]
log.Warnf("%s %s - %s", st.Render("⚠"), codeStyle.Render(tool), st.Render("not present in path"))
return err
}
st := lipgloss.NewStyle().Foreground(lipgloss.Color("2")).Bold(true)
log.Infof("%s %s", st.Render("✓"), codeStyle.Render(tool))
return nil
}