diff --git a/goreleaserlib/goreleaser.go b/goreleaserlib/goreleaser.go deleted file mode 100644 index 47bacb3fe..000000000 --- a/goreleaserlib/goreleaser.go +++ /dev/null @@ -1,192 +0,0 @@ -package goreleaserlib - -import ( - "fmt" - "io/ioutil" - "os" - "strings" - "time" - - "github.com/apex/log" - "github.com/apex/log/handlers/cli" - "github.com/caarlos0/ctrlc" - "github.com/fatih/color" - yaml "gopkg.in/yaml.v2" - - "github.com/goreleaser/goreleaser/config" - "github.com/goreleaser/goreleaser/context" - "github.com/goreleaser/goreleaser/pipeline" - "github.com/goreleaser/goreleaser/pipeline/archive" - "github.com/goreleaser/goreleaser/pipeline/artifactory" - "github.com/goreleaser/goreleaser/pipeline/brew" - "github.com/goreleaser/goreleaser/pipeline/build" - "github.com/goreleaser/goreleaser/pipeline/changelog" - "github.com/goreleaser/goreleaser/pipeline/checksums" - "github.com/goreleaser/goreleaser/pipeline/defaults" - "github.com/goreleaser/goreleaser/pipeline/dist" - "github.com/goreleaser/goreleaser/pipeline/docker" - "github.com/goreleaser/goreleaser/pipeline/effectiveconfig" - "github.com/goreleaser/goreleaser/pipeline/env" - "github.com/goreleaser/goreleaser/pipeline/fpm" - "github.com/goreleaser/goreleaser/pipeline/git" - "github.com/goreleaser/goreleaser/pipeline/nfpm" - "github.com/goreleaser/goreleaser/pipeline/release" - "github.com/goreleaser/goreleaser/pipeline/scoop" - "github.com/goreleaser/goreleaser/pipeline/sign" - "github.com/goreleaser/goreleaser/pipeline/snapcraft" -) - -var ( - normalPadding = cli.Default.Padding - increasedPadding = normalPadding * 2 -) - -func init() { - log.SetHandler(cli.Default) -} - -var pipes = []pipeline.Piper{ - defaults.Pipe{}, // load default configs - dist.Pipe{}, // ensure ./dist is clean - git.Pipe{}, // get and validate git repo state - effectiveconfig.Pipe{}, // writes the actual config (with defaults et al set) to dist - changelog.Pipe{}, // builds the release changelog - env.Pipe{}, // load and validate environment variables - build.Pipe{}, // build - archive.Pipe{}, // archive in tar.gz, zip or binary (which does no archiving at all) - fpm.Pipe{}, // archive via fpm (deb, rpm) using fpm - nfpm.Pipe{}, // archive via fpm (deb, rpm) using "native" go impl - snapcraft.Pipe{}, // archive via snapcraft (snap) - checksums.Pipe{}, // checksums of the files - sign.Pipe{}, // sign artifacts - docker.Pipe{}, // create and push docker images - artifactory.Pipe{}, // push to artifactory - release.Pipe{}, // release to github - brew.Pipe{}, // push to brew tap - scoop.Pipe{}, // push to scoop bucket -} - -// Flags interface represents an extractor of cli flags -type Flags interface { - IsSet(s string) bool - String(s string) string - Int(s string) int - Bool(s string) bool - Duration(s string) time.Duration -} - -// Release runs the release process with the given flags -func Release(flags Flags) error { - var file = getConfigFile(flags) - var notes = flags.String("release-notes") - if flags.Bool("debug") { - log.SetLevel(log.DebugLevel) - } - cfg, err := config.Load(file) - if err != nil { - // Allow file not found errors if config file was not - // explicitly specified - _, statErr := os.Stat(file) - if !os.IsNotExist(statErr) || flags.IsSet("config") { - return err - } - log.WithField("file", file).Warn("could not load config, using defaults") - } - ctx, cancel := context.NewWithTimeout(cfg, flags.Duration("timeout")) - defer cancel() - ctx.Parallelism = flags.Int("parallelism") - ctx.Debug = flags.Bool("debug") - log.Debugf("parallelism: %v", ctx.Parallelism) - ctx.Validate = !flags.Bool("skip-validate") - ctx.Publish = !flags.Bool("skip-publish") - if notes != "" { - bts, err := ioutil.ReadFile(notes) - if err != nil { - return err - } - log.WithField("file", notes).Info("loaded custom release notes") - log.WithField("file", notes).Debugf("custom release notes: \n%s", string(bts)) - ctx.ReleaseNotes = string(bts) - } - ctx.Snapshot = flags.Bool("snapshot") - if ctx.Snapshot { - log.Info("publishing disabled in snapshot mode") - ctx.Publish = false - } - ctx.RmDist = flags.Bool("rm-dist") - return doRelease(ctx) -} - -func doRelease(ctx *context.Context) error { - defer restoreOutputPadding() - return ctrlc.Default.Run(ctx, func() error { - for _, pipe := range pipes { - restoreOutputPadding() - log.Infof(color.New(color.Bold).Sprint(strings.ToUpper(pipe.String()))) - cli.Default.Padding = increasedPadding - if err := handle(pipe.Run(ctx)); err != nil { - return err - } - } - return nil - }) -} - -func restoreOutputPadding() { - cli.Default.Padding = normalPadding -} - -func handle(err error) error { - if err == nil { - return nil - } - if pipeline.IsSkip(err) { - log.WithField("reason", err.Error()).Warn("skipped") - return nil - } - return err -} - -// 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) - } - - var ctx = context.New(config.Project{}) - var pipe = defaults.Pipe{} - defer restoreOutputPadding() - log.Infof(color.New(color.Bold).Sprint(strings.ToUpper(pipe.String()))) - cli.Default.Padding = increasedPadding - if err := pipe.Run(ctx); err != nil { - return err - } - out, err := yaml.Marshal(ctx.Config) - if err != nil { - return err - } - - return ioutil.WriteFile(filename, out, 0644) -} - -func getConfigFile(flags Flags) string { - var config = flags.String("config") - if flags.IsSet("config") { - return config - } - for _, f := range []string{ - ".goreleaser.yml", - ".goreleaser.yaml", - "goreleaser.yml", - "goreleaser.yaml", - } { - _, ferr := os.Stat(f) - if ferr == nil || os.IsExist(ferr) { - return f - } - } - return config -} diff --git a/main.go b/main.go index 7c90e8a63..bfe039912 100644 --- a/main.go +++ b/main.go @@ -2,14 +2,40 @@ package main import ( "fmt" + "io/ioutil" "os" + "strings" "time" "github.com/apex/log" lcli "github.com/apex/log/handlers/cli" + "github.com/caarlos0/ctrlc" + yaml "gopkg.in/yaml.v2" + "github.com/fatih/color" - "github.com/goreleaser/goreleaser/goreleaserlib" "github.com/urfave/cli" + + "github.com/goreleaser/goreleaser/config" + "github.com/goreleaser/goreleaser/context" + "github.com/goreleaser/goreleaser/pipeline" + "github.com/goreleaser/goreleaser/pipeline/archive" + "github.com/goreleaser/goreleaser/pipeline/artifactory" + "github.com/goreleaser/goreleaser/pipeline/brew" + "github.com/goreleaser/goreleaser/pipeline/build" + "github.com/goreleaser/goreleaser/pipeline/changelog" + "github.com/goreleaser/goreleaser/pipeline/checksums" + "github.com/goreleaser/goreleaser/pipeline/defaults" + "github.com/goreleaser/goreleaser/pipeline/dist" + "github.com/goreleaser/goreleaser/pipeline/docker" + "github.com/goreleaser/goreleaser/pipeline/effectiveconfig" + "github.com/goreleaser/goreleaser/pipeline/env" + "github.com/goreleaser/goreleaser/pipeline/fpm" + "github.com/goreleaser/goreleaser/pipeline/git" + "github.com/goreleaser/goreleaser/pipeline/nfpm" + "github.com/goreleaser/goreleaser/pipeline/release" + "github.com/goreleaser/goreleaser/pipeline/scoop" + "github.com/goreleaser/goreleaser/pipeline/sign" + "github.com/goreleaser/goreleaser/pipeline/snapcraft" ) var ( @@ -17,9 +43,41 @@ var ( commit = "none" date = "unknown" - bold = color.New(color.Bold) + bold = color.New(color.Bold) + normalPadding = lcli.Default.Padding + increasedPadding = normalPadding * 2 + + pipes = []pipeline.Piper{ + defaults.Pipe{}, // load default configs + dist.Pipe{}, // ensure ./dist is clean + git.Pipe{}, // get and validate git repo state + effectiveconfig.Pipe{}, // writes the actual config (with defaults et al set) to dist + changelog.Pipe{}, // builds the release changelog + env.Pipe{}, // load and validate environment variables + build.Pipe{}, // build + archive.Pipe{}, // archive in tar.gz, zip or binary (which does no archiving at all) + fpm.Pipe{}, // archive via fpm (deb, rpm) using fpm + nfpm.Pipe{}, // archive via fpm (deb, rpm) using "native" go impl + snapcraft.Pipe{}, // archive via snapcraft (snap) + checksums.Pipe{}, // checksums of the files + sign.Pipe{}, // sign artifacts + docker.Pipe{}, // create and push docker images + artifactory.Pipe{}, // push to artifactory + release.Pipe{}, // release to github + brew.Pipe{}, // push to brew tap + scoop.Pipe{}, // push to scoop bucket + } ) +// Flags interface represents an extractor of cli flags +type Flags interface { + IsSet(s string) bool + String(s string) string + Int(s string) int + Bool(s string) bool + Duration(s string) time.Duration +} + func init() { log.SetHandler(lcli.Default) } @@ -75,7 +133,7 @@ func main() { app.Action = func(c *cli.Context) error { start := time.Now() log.Infof(bold.Sprint("releasing...")) - if err := goreleaserlib.Release(c); err != nil { + if err := releaseProject(c); err != nil { log.WithError(err).Errorf(bold.Sprintf("release failed after %0.2fs", time.Since(start).Seconds())) return cli.NewExitError("\n", 1) } @@ -89,7 +147,7 @@ func main() { Usage: "generate .goreleaser.yml", Action: func(c *cli.Context) error { var filename = ".goreleaser.yml" - if err := goreleaserlib.InitProject(filename); err != nil { + if err := initProject(filename); err != nil { log.WithError(err).Error("failed to init project") return cli.NewExitError("\n", 1) } @@ -104,3 +162,118 @@ func main() { log.WithError(err).Fatal("failed") } } + +func releaseProject(flags Flags) error { + var file = getConfigFile(flags) + var notes = flags.String("release-notes") + if flags.Bool("debug") { + log.SetLevel(log.DebugLevel) + } + cfg, err := config.Load(file) + if err != nil { + // Allow file not found errors if config file was not + // explicitly specified + _, statErr := os.Stat(file) + if !os.IsNotExist(statErr) || flags.IsSet("config") { + return err + } + log.WithField("file", file).Warn("could not load config, using defaults") + } + ctx, cancel := context.NewWithTimeout(cfg, flags.Duration("timeout")) + defer cancel() + ctx.Parallelism = flags.Int("parallelism") + ctx.Debug = flags.Bool("debug") + log.Debugf("parallelism: %v", ctx.Parallelism) + ctx.Validate = !flags.Bool("skip-validate") + ctx.Publish = !flags.Bool("skip-publish") + if notes != "" { + bts, err := ioutil.ReadFile(notes) + if err != nil { + return err + } + log.WithField("file", notes).Info("loaded custom release notes") + log.WithField("file", notes).Debugf("custom release notes: \n%s", string(bts)) + ctx.ReleaseNotes = string(bts) + } + ctx.Snapshot = flags.Bool("snapshot") + if ctx.Snapshot { + log.Info("publishing disabled in snapshot mode") + ctx.Publish = false + } + ctx.RmDist = flags.Bool("rm-dist") + return doRelease(ctx) +} + +func doRelease(ctx *context.Context) error { + defer restoreOutputPadding() + return ctrlc.Default.Run(ctx, func() error { + for _, pipe := range pipes { + restoreOutputPadding() + log.Infof(color.New(color.Bold).Sprint(strings.ToUpper(pipe.String()))) + lcli.Default.Padding = increasedPadding + if err := handle(pipe.Run(ctx)); err != nil { + return err + } + } + return nil + }) +} + +func restoreOutputPadding() { + lcli.Default.Padding = normalPadding +} + +func handle(err error) error { + if err == nil { + return nil + } + if pipeline.IsSkip(err) { + log.WithField("reason", err.Error()).Warn("skipped") + return nil + } + return err +} + +// 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) + } + + var ctx = context.New(config.Project{}) + var pipe = defaults.Pipe{} + defer restoreOutputPadding() + log.Infof(color.New(color.Bold).Sprint(strings.ToUpper(pipe.String()))) + lcli.Default.Padding = increasedPadding + if err := pipe.Run(ctx); err != nil { + return err + } + out, err := yaml.Marshal(ctx.Config) + if err != nil { + return err + } + + return ioutil.WriteFile(filename, out, 0644) +} + +func getConfigFile(flags Flags) string { + var config = flags.String("config") + if flags.IsSet("config") { + return config + } + for _, f := range []string{ + ".goreleaser.yml", + ".goreleaser.yaml", + "goreleaser.yml", + "goreleaser.yaml", + } { + _, ferr := os.Stat(f) + if ferr == nil || os.IsExist(ferr) { + return f + } + } + return config +} diff --git a/goreleaserlib/goreleaser_test.go b/main_test.go similarity index 87% rename from goreleaserlib/goreleaser_test.go rename to main_test.go index 08153f381..349ecb604 100644 --- a/goreleaserlib/goreleaser_test.go +++ b/main_test.go @@ -1,4 +1,4 @@ -package goreleaserlib +package main import ( "io/ioutil" @@ -18,24 +18,24 @@ func init() { _ = os.Unsetenv("GITHUB_TOKEN") } -func TestRelease(t *testing.T) { +func TestReleaseProject(t *testing.T) { _, back := setup(t) defer back() - assert.NoError(t, Release(newFlags(t, testParams()))) + assert.NoError(t, releaseProject(newFlags(t, testParams()))) } -func TestSnapshotRelease(t *testing.T) { +func TestSnapshotreleaseProject(t *testing.T) { _, back := setup(t) defer back() params := testParams() params["snapshot"] = "true" - assert.NoError(t, Release(newFlags(t, params))) + assert.NoError(t, releaseProject(newFlags(t, params))) } func TestConfigFileIsSetAndDontExist(t *testing.T) { params := testParams() params["config"] = "/this/wont/exist" - assert.Error(t, Release(newFlags(t, params))) + assert.Error(t, releaseProject(newFlags(t, params))) } func TestConfigFlagNotSetButExists(t *testing.T) { @@ -63,7 +63,7 @@ func TestConfigFlagNotSetButExists(t *testing.T) { func TestReleaseNotesFileDontExist(t *testing.T) { params := testParams() params["release-notes"] = "/this/also/wont/exist" - assert.Error(t, Release(newFlags(t, params))) + assert.Error(t, releaseProject(newFlags(t, params))) } func TestCustomReleaseNotesFile(t *testing.T) { @@ -73,21 +73,21 @@ func TestCustomReleaseNotesFile(t *testing.T) { createFile(t, releaseNotes, "nothing important at all") var params = testParams() params["release-notes"] = releaseNotes - assert.NoError(t, Release(newFlags(t, params))) + assert.NoError(t, releaseProject(newFlags(t, params))) } func TestBrokenPipe(t *testing.T) { _, back := setup(t) defer back() createFile(t, "main.go", "not a valid go file") - assert.Error(t, Release(newFlags(t, testParams()))) + assert.Error(t, releaseProject(newFlags(t, testParams()))) } func TestInitProject(t *testing.T) { _, back := setup(t) defer back() var filename = "test_goreleaser.yml" - assert.NoError(t, InitProject(filename)) + assert.NoError(t, initProject(filename)) file, err := os.Open(filename) assert.NoError(t, err) @@ -103,7 +103,7 @@ func TestInitProjectFileExist(t *testing.T) { defer back() var filename = "test_goreleaser.yml" createFile(t, filename, "") - assert.Error(t, InitProject(filename)) + assert.Error(t, initProject(filename)) } func TestInitProjectDefaultPipeFails(t *testing.T) { @@ -111,7 +111,7 @@ func TestInitProjectDefaultPipeFails(t *testing.T) { defer back() var filename = "test_goreleaser.yml" assert.NoError(t, os.RemoveAll(".git")) - assert.Error(t, InitProject(filename)) + assert.Error(t, initProject(filename)) } // fakeFlags is a mock of the cli flags