github.com/windmeup/goreleaser@v1.21.95/internal/pipe/before/before.go (about)

     1  // Package before provides the pipe implementation that runs before all other pipes.
     2  package before
     3  
     4  import (
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"os/exec"
     9  
    10  	"github.com/caarlos0/go-shellwords"
    11  	"github.com/caarlos0/log"
    12  	"github.com/windmeup/goreleaser/internal/gio"
    13  	"github.com/windmeup/goreleaser/internal/logext"
    14  	"github.com/windmeup/goreleaser/internal/skips"
    15  	"github.com/windmeup/goreleaser/internal/tmpl"
    16  	"github.com/windmeup/goreleaser/pkg/context"
    17  )
    18  
    19  // Pipe is a global hook pipe.
    20  type Pipe struct{}
    21  
    22  func (Pipe) String() string { return "running before hooks" }
    23  
    24  func (Pipe) Skip(ctx *context.Context) bool {
    25  	return len(ctx.Config.Before.Hooks) == 0 || skips.Any(ctx, skips.Before)
    26  }
    27  
    28  // Run executes the hooks.
    29  func (Pipe) Run(ctx *context.Context) error {
    30  	tmpl := tmpl.New(ctx)
    31  	/* #nosec */
    32  	for _, step := range ctx.Config.Before.Hooks {
    33  		s, err := tmpl.Apply(step)
    34  		if err != nil {
    35  			return err
    36  		}
    37  		args, err := shellwords.Parse(s)
    38  		if err != nil {
    39  			return err
    40  		}
    41  
    42  		cmd := exec.Command(args[0], args[1:]...)
    43  		cmd.Env = ctx.Env.Strings()
    44  
    45  		var b bytes.Buffer
    46  		w := gio.Safe(&b)
    47  		cmd.Stderr = io.MultiWriter(logext.NewWriter(), w)
    48  		cmd.Stdout = io.MultiWriter(logext.NewWriter(), w)
    49  
    50  		log.WithField("hook", step).Info("running")
    51  		if err := cmd.Run(); err != nil {
    52  			return fmt.Errorf("hook failed: %s: %w; output: %s", step, err, b.String())
    53  		}
    54  	}
    55  	return nil
    56  }