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 }