2017-04-21 20:25:32 +02:00
package main
import (
2017-04-22 02:58:59 +02:00
"fmt"
2018-02-22 01:04:22 +02:00
"io/ioutil"
2017-04-21 20:25:32 +02:00
"os"
2017-12-06 05:02:52 +02:00
"time"
2017-04-21 20:25:32 +02:00
2017-06-22 05:09:14 +02:00
"github.com/apex/log"
2018-03-11 17:00:47 +02:00
"github.com/apex/log/handlers/cli"
2018-02-24 22:59:08 +02:00
"github.com/caarlos0/ctrlc"
2018-01-17 22:48:01 +02:00
"github.com/fatih/color"
2019-01-22 05:56:16 +02:00
"github.com/goreleaser/goreleaser/internal/middleware"
2018-08-15 04:50:20 +02:00
"github.com/goreleaser/goreleaser/internal/pipeline"
2019-01-22 05:12:17 +02:00
"github.com/goreleaser/goreleaser/internal/static"
2018-08-15 04:50:20 +02:00
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
2019-08-02 21:37:50 +02:00
"github.com/goreleaser/goreleaser/pkg/defaults"
2019-01-22 05:12:17 +02:00
kingpin "gopkg.in/alecthomas/kingpin.v2"
2017-04-21 20:25:32 +02:00
)
2018-11-08 02:04:49 +02:00
// nolint: gochecknoglobals
2017-04-21 20:25:32 +02:00
var (
version = "dev"
2019-05-28 04:59:33 +02:00
commit = ""
date = ""
builtBy = ""
2017-04-21 20:25:32 +02:00
)
2018-03-11 17:00:47 +02:00
type releaseOptions struct {
Config string
ReleaseNotes string
Snapshot bool
SkipPublish bool
2018-05-24 10:50:14 +02:00
SkipSign bool
2018-03-11 17:00:47 +02:00
SkipValidate bool
RmDist bool
Parallelism int
Timeout time . Duration
2018-02-22 01:04:22 +02:00
}
2018-11-08 02:04:49 +02:00
func main ( ) {
2018-10-26 16:30:03 +02:00
// enable colored output on travis
2018-10-26 23:19:51 +02:00
if os . Getenv ( "CI" ) != "" {
2018-10-26 16:30:03 +02:00
color . NoColor = false
}
2018-03-11 17:00:47 +02:00
log . SetHandler ( cli . Default )
2017-06-22 05:09:14 +02:00
2017-11-27 01:48:05 +02:00
fmt . Println ( )
defer fmt . Println ( )
2018-03-11 17:00:47 +02:00
var app = kingpin . New ( "goreleaser" , "Deliver Go binaries as fast and easily as possible" )
2019-01-22 05:12:17 +02:00
var debug = app . Flag ( "debug" , "Enable debug mode" ) . Bool ( )
2019-08-02 21:37:50 +02:00
var config = app . Flag ( "config" , "Load configuration from file" ) . Short ( 'c' ) . Short ( 'f' ) . PlaceHolder ( ".goreleaser.yml" ) . String ( )
2018-03-11 17:09:19 +02:00
var initCmd = app . Command ( "init" , "Generates a .goreleaser.yml file" ) . Alias ( "i" )
2019-08-02 21:37:50 +02:00
var checkCmd = app . Command ( "check" , "Checks if configuration is valid" ) . Alias ( "c" )
2018-03-11 17:09:19 +02:00
var releaseCmd = app . Command ( "release" , "Releases the current project" ) . Alias ( "r" ) . Default ( )
2018-03-11 17:03:35 +02:00
var releaseNotes = releaseCmd . Flag ( "release-notes" , "Load custom release notes from a markdown file" ) . PlaceHolder ( "notes.md" ) . String ( )
2018-03-11 17:00:47 +02:00
var snapshot = releaseCmd . Flag ( "snapshot" , "Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts" ) . Bool ( )
2019-01-22 05:56:16 +02:00
var skipPublish = releaseCmd . Flag ( "skip-publish" , "Skips publishing artifacts" ) . Bool ( )
2018-05-24 10:50:14 +02:00
var skipSign = releaseCmd . Flag ( "skip-sign" , "Skips signing the artifacts" ) . Bool ( )
2019-01-22 05:56:16 +02:00
var skipValidate = releaseCmd . Flag ( "skip-validate" , "Skips several sanity checks" ) . Bool ( )
2018-03-11 17:00:47 +02:00
var rmDist = releaseCmd . Flag ( "rm-dist" , "Remove the dist folder before building" ) . Bool ( )
2019-01-22 05:56:16 +02:00
var parallelism = releaseCmd . Flag ( "parallelism" , "Amount tasks to run concurrently" ) . Short ( 'p' ) . Default ( "4" ) . Int ( )
2018-03-11 17:00:47 +02:00
var timeout = releaseCmd . Flag ( "timeout" , "Timeout to the entire release process" ) . Default ( "30m" ) . Duration ( )
2019-05-28 04:59:33 +02:00
app . Version ( buildVersion ( version , commit , date , builtBy ) )
2018-03-11 17:00:47 +02:00
app . VersionFlag . Short ( 'v' )
app . HelpFlag . Short ( 'h' )
2019-01-22 05:12:17 +02:00
app . UsageTemplate ( static . UsageTemplate )
2018-03-11 17:00:47 +02:00
2019-01-22 05:12:17 +02:00
cmd := kingpin . MustParse ( app . Parse ( os . Args [ 1 : ] ) )
if * debug {
log . SetLevel ( log . DebugLevel )
}
switch cmd {
2018-03-11 17:00:47 +02:00
case initCmd . FullCommand ( ) :
2019-08-02 21:37:50 +02:00
var filename = * config
2018-03-11 17:00:47 +02:00
if err := initProject ( filename ) ; err != nil {
log . WithError ( err ) . Error ( "failed to init project" )
2019-01-22 05:12:17 +02:00
os . Exit ( 1 )
2018-03-11 17:00:47 +02:00
return
}
log . WithField ( "file" , filename ) . Info ( "config created; please edit accordingly to your needs" )
2019-08-02 21:37:50 +02:00
case checkCmd . FullCommand ( ) :
if err := checkConfig ( * config ) ; err != nil {
log . WithError ( err ) . Errorf ( color . New ( color . Bold ) . Sprintf ( "config is invalid" ) )
os . Exit ( 1 )
return
}
log . Infof ( color . New ( color . Bold ) . Sprintf ( "config is valid" ) )
2018-03-11 17:00:47 +02:00
case releaseCmd . FullCommand ( ) :
2017-12-06 05:02:52 +02:00
start := time . Now ( )
2018-03-11 17:00:47 +02:00
log . Infof ( color . New ( color . Bold ) . Sprintf ( "releasing using goreleaser %s..." , version ) )
var options = releaseOptions {
Config : * config ,
ReleaseNotes : * releaseNotes ,
Snapshot : * snapshot ,
SkipPublish : * skipPublish ,
SkipValidate : * skipValidate ,
2018-05-24 10:50:14 +02:00
SkipSign : * skipSign ,
2018-03-11 17:00:47 +02:00
RmDist : * rmDist ,
Parallelism : * parallelism ,
Timeout : * timeout ,
2017-04-21 20:25:32 +02:00
}
2018-03-11 17:00:47 +02:00
if err := releaseProject ( options ) ; err != nil {
log . WithError ( err ) . Errorf ( color . New ( color . Bold ) . Sprintf ( "release failed after %0.2fs" , time . Since ( start ) . Seconds ( ) ) )
2019-01-22 05:12:17 +02:00
os . Exit ( 1 )
2018-03-11 17:00:47 +02:00
return
}
log . Infof ( color . New ( color . Bold ) . Sprintf ( "release succeeded after %0.2fs" , time . Since ( start ) . Seconds ( ) ) )
2017-04-21 20:25:32 +02:00
}
2018-03-11 17:00:47 +02:00
}
2017-04-27 11:03:26 +02:00
2019-08-02 21:37:50 +02:00
func checkConfig ( filename string ) error {
cfg , err := loadConfig ( filename )
if err != nil {
return err
}
var ctx = context . New ( cfg )
return ctrlc . Default . Run ( ctx , func ( ) error {
for _ , pipe := range defaults . Defaulters {
if err := middleware . ErrHandler ( pipe . Default ) ( ctx ) ; err != nil {
return err
}
}
return nil
} )
}
2018-03-11 17:00:47 +02:00
func releaseProject ( options releaseOptions ) error {
cfg , err := loadConfig ( options . Config )
2018-02-22 01:04:22 +02:00
if err != nil {
2018-03-11 17:00:47 +02:00
return err
2018-02-22 01:04:22 +02:00
}
2018-03-11 17:00:47 +02:00
ctx , cancel := context . NewWithTimeout ( cfg , options . Timeout )
2018-02-22 01:04:22 +02:00
defer cancel ( )
2018-03-11 17:00:47 +02:00
ctx . Parallelism = options . Parallelism
2018-02-22 01:04:22 +02:00
log . Debugf ( "parallelism: %v" , ctx . Parallelism )
2019-01-22 05:56:16 +02:00
ctx . ReleaseNotes = options . ReleaseNotes
2018-03-11 17:00:47 +02:00
ctx . Snapshot = options . Snapshot
ctx . SkipPublish = ctx . Snapshot || options . SkipPublish
ctx . SkipValidate = ctx . Snapshot || options . SkipValidate
2018-05-24 10:50:14 +02:00
ctx . SkipSign = options . SkipSign
2018-03-11 17:00:47 +02:00
ctx . RmDist = options . RmDist
2019-01-22 05:56:16 +02:00
return ctrlc . Default . Run ( ctx , func ( ) error {
2018-09-12 19:18:01 +02:00
for _ , pipe := range pipeline . Pipeline {
2019-01-22 05:56:16 +02:00
if err := middleware . Logging (
pipe . String ( ) ,
middleware . ErrHandler ( pipe . Run ) ,
middleware . DefaultInitialPadding ,
) ( ctx ) ; err != nil {
2018-02-22 01:04:22 +02:00
return err
}
}
return nil
2019-01-22 05:56:16 +02:00
} )
2018-02-22 01:04:22 +02:00
}
// InitProject creates an example goreleaser.yml in the current directory
func initProject ( filename string ) error {
if _ , err := os . Stat ( filename ) ; ! os . IsNotExist ( err ) {
if err != nil {
return err
}
return fmt . Errorf ( "%s already exists" , filename )
}
2018-03-11 17:00:47 +02:00
log . Infof ( color . New ( color . Bold ) . Sprintf ( "Generating %s file" , filename ) )
2019-01-22 05:12:17 +02:00
return ioutil . WriteFile ( filename , [ ] byte ( static . ExampleConfig ) , 0644 )
2018-02-22 01:04:22 +02:00
}
2018-03-11 17:00:47 +02:00
func loadConfig ( path string ) ( config . Project , error ) {
if path != "" {
return config . Load ( path )
2018-02-22 01:04:22 +02:00
}
2018-03-11 17:00:47 +02:00
for _ , f := range [ 4 ] string {
2018-02-22 01:04:22 +02:00
".goreleaser.yml" ,
".goreleaser.yaml" ,
"goreleaser.yml" ,
"goreleaser.yaml" ,
} {
2018-03-11 17:00:47 +02:00
proj , err := config . Load ( f )
if err != nil && os . IsNotExist ( err ) {
continue
2018-02-22 01:04:22 +02:00
}
2018-03-11 17:00:47 +02:00
return proj , err
2018-02-22 01:04:22 +02:00
}
2019-02-01 18:09:23 +02:00
// the user didn't specify a config file and the known possible file names
2019-01-22 05:56:16 +02:00
// don't exist, so, return an empty config and a nil err.
2019-02-01 18:09:23 +02:00
log . Warn ( "could not find a config file, using defaults..." )
2018-03-11 17:00:47 +02:00
return config . Project { } , nil
2018-02-22 01:04:22 +02:00
}
2019-05-28 04:59:33 +02:00
func buildVersion ( version , commit , date , builtBy string ) string {
var result = fmt . Sprintf ( "version: %s" , version )
if commit != "" {
result = fmt . Sprintf ( "%s\ncommit: %s" , result , commit )
}
if date != "" {
result = fmt . Sprintf ( "%s\nbuilt at: %s" , result , date )
}
if builtBy != "" {
result = fmt . Sprintf ( "%s\nbuilt by: %s" , result , builtBy )
}
return result
}