gitee.com/mirrors_opencollective/goreleaser@v0.45.0/goreleaserlib/goreleaser.go (about)

     1  package goreleaserlib
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/apex/log"
    11  	"github.com/apex/log/handlers/cli"
    12  	"github.com/caarlos0/ctrlc"
    13  	"github.com/fatih/color"
    14  	yaml "gopkg.in/yaml.v2"
    15  
    16  	"github.com/goreleaser/goreleaser/config"
    17  	"github.com/goreleaser/goreleaser/context"
    18  	"github.com/goreleaser/goreleaser/pipeline"
    19  	"github.com/goreleaser/goreleaser/pipeline/archive"
    20  	"github.com/goreleaser/goreleaser/pipeline/artifactory"
    21  	"github.com/goreleaser/goreleaser/pipeline/brew"
    22  	"github.com/goreleaser/goreleaser/pipeline/build"
    23  	"github.com/goreleaser/goreleaser/pipeline/changelog"
    24  	"github.com/goreleaser/goreleaser/pipeline/checksums"
    25  	"github.com/goreleaser/goreleaser/pipeline/defaults"
    26  	"github.com/goreleaser/goreleaser/pipeline/dist"
    27  	"github.com/goreleaser/goreleaser/pipeline/docker"
    28  	"github.com/goreleaser/goreleaser/pipeline/effectiveconfig"
    29  	"github.com/goreleaser/goreleaser/pipeline/env"
    30  	"github.com/goreleaser/goreleaser/pipeline/fpm"
    31  	"github.com/goreleaser/goreleaser/pipeline/git"
    32  	"github.com/goreleaser/goreleaser/pipeline/release"
    33  	"github.com/goreleaser/goreleaser/pipeline/sign"
    34  	"github.com/goreleaser/goreleaser/pipeline/snapcraft"
    35  )
    36  
    37  var (
    38  	normalPadding    = cli.Default.Padding
    39  	increasedPadding = normalPadding * 2
    40  )
    41  
    42  func init() {
    43  	log.SetHandler(cli.Default)
    44  }
    45  
    46  var pipes = []pipeline.Piper{
    47  	defaults.Pipe{},        // load default configs
    48  	dist.Pipe{},            // ensure ./dist is clean
    49  	git.Pipe{},             // get and validate git repo state
    50  	effectiveconfig.Pipe{}, // writes the actual config (with defaults et al set) to dist
    51  	changelog.Pipe{},       // builds the release changelog
    52  	env.Pipe{},             // load and validate environment variables
    53  	build.Pipe{},           // build
    54  	archive.Pipe{},         // archive (tar.gz, zip, etc)
    55  	fpm.Pipe{},             // archive via fpm (deb, rpm, etc)
    56  	snapcraft.Pipe{},       // archive via snapcraft (snap)
    57  	checksums.Pipe{},       // checksums of the files
    58  	sign.Pipe{},            // sign artifacts
    59  	docker.Pipe{},          // create and push docker images
    60  	artifactory.Pipe{},     // push to artifactory
    61  	release.Pipe{},         // release to github
    62  	brew.Pipe{},            // push to brew tap
    63  }
    64  
    65  // Flags interface represents an extractor of cli flags
    66  type Flags interface {
    67  	IsSet(s string) bool
    68  	String(s string) string
    69  	Int(s string) int
    70  	Bool(s string) bool
    71  	Duration(s string) time.Duration
    72  }
    73  
    74  // Release runs the release process with the given flags
    75  func Release(flags Flags) error {
    76  	var file = getConfigFile(flags)
    77  	var notes = flags.String("release-notes")
    78  	if flags.Bool("debug") {
    79  		log.SetLevel(log.DebugLevel)
    80  	}
    81  	cfg, err := config.Load(file)
    82  	if err != nil {
    83  		// Allow file not found errors if config file was not
    84  		// explicitly specified
    85  		_, statErr := os.Stat(file)
    86  		if !os.IsNotExist(statErr) || flags.IsSet("config") {
    87  			return err
    88  		}
    89  		log.WithField("file", file).Warn("could not load config, using defaults")
    90  	}
    91  	ctx, cancel := context.NewWithTimeout(cfg, flags.Duration("timeout"))
    92  	defer cancel()
    93  	ctx.Parallelism = flags.Int("parallelism")
    94  	ctx.Debug = flags.Bool("debug")
    95  	log.Debugf("parallelism: %v", ctx.Parallelism)
    96  	ctx.Validate = !flags.Bool("skip-validate")
    97  	ctx.Publish = !flags.Bool("skip-publish")
    98  	if notes != "" {
    99  		bts, err := ioutil.ReadFile(notes)
   100  		if err != nil {
   101  			return err
   102  		}
   103  		log.WithField("file", notes).Info("loaded custom release notes")
   104  		log.WithField("file", notes).Debugf("custon release notes: \n%s", string(bts))
   105  		ctx.ReleaseNotes = string(bts)
   106  	}
   107  	ctx.Snapshot = flags.Bool("snapshot")
   108  	if ctx.Snapshot {
   109  		log.Info("publishing disabled in snapshot mode")
   110  		ctx.Publish = false
   111  	}
   112  	ctx.RmDist = flags.Bool("rm-dist")
   113  	return doRelease(ctx)
   114  }
   115  
   116  func doRelease(ctx *context.Context) error {
   117  	defer restoreOutputPadding()
   118  	return ctrlc.Default.Run(ctx, func() error {
   119  		for _, pipe := range pipes {
   120  			restoreOutputPadding()
   121  			log.Infof(color.New(color.Bold).Sprint(strings.ToUpper(pipe.String())))
   122  			cli.Default.Padding = increasedPadding
   123  			if err := handle(pipe.Run(ctx)); err != nil {
   124  				return err
   125  			}
   126  		}
   127  		return nil
   128  	})
   129  }
   130  
   131  func restoreOutputPadding() {
   132  	cli.Default.Padding = normalPadding
   133  }
   134  
   135  func handle(err error) error {
   136  	if err == nil {
   137  		return nil
   138  	}
   139  	if pipeline.IsSkip(err) {
   140  		log.WithField("reason", err.Error()).Warn("skipped")
   141  		return nil
   142  	}
   143  	return err
   144  }
   145  
   146  // InitProject creates an example goreleaser.yml in the current directory
   147  func InitProject(filename string) error {
   148  	if _, err := os.Stat(filename); !os.IsNotExist(err) {
   149  		if err != nil {
   150  			return err
   151  		}
   152  		return fmt.Errorf("%s already exists", filename)
   153  	}
   154  
   155  	var ctx = context.New(config.Project{})
   156  	var pipe = defaults.Pipe{}
   157  	if err := pipe.Run(ctx); err != nil {
   158  		return err
   159  	}
   160  	out, err := yaml.Marshal(ctx.Config)
   161  	if err != nil {
   162  		return err
   163  	}
   164  
   165  	return ioutil.WriteFile(filename, out, 0644)
   166  }
   167  
   168  func getConfigFile(flags Flags) string {
   169  	var config = flags.String("config")
   170  	if flags.IsSet("config") {
   171  		return config
   172  	}
   173  	for _, f := range []string{
   174  		".goreleaser.yml",
   175  		".goreleaser.yaml",
   176  		"goreleaser.yml",
   177  		"goreleaser.yaml",
   178  	} {
   179  		_, ferr := os.Stat(f)
   180  		if ferr == nil || os.IsExist(ferr) {
   181  			return f
   182  		}
   183  	}
   184  	return config
   185  }